كيف تعمل مخفضات الاختزال
نشرت: 2022-03-10state
، فمن المؤكد أنك ستصادف مخفضات. سيشرح هذا البرنامج التعليمي مفهوم المخفضات وكيف تعمل بشكل خاص في Redux.في هذا البرنامج التعليمي ، سنتعلم مفهوم المخفضات وكيفية عملها ، وتحديداً في تطبيقات React. من أجل فهم Redux واستخدامه بشكل أفضل ، يعد الفهم القوي للمخفضات أمرًا ضروريًا. توفر المخفضات طريقة لتحديث حالة التطبيق باستخدام إجراء. إنه جزء لا يتجزأ من مكتبة Redux.
هذا البرنامج التعليمي مخصص للمطورين الذين يرغبون في معرفة المزيد عن Redux Reducers. سيكون فهم React و Redux مفيدًا. في نهاية البرنامج التعليمي ، يجب أن يكون لديك فهم أفضل للدور الذي تلعبه Reducers في Redux. سنقوم بكتابة عروض الكود والتطبيق لفهم أفضل للمخفّضين وكيفية تأثيره على الحالة في التطبيق.
ما هو المخفض
المخفض هو وظيفة خالصة تأخذ حالة التطبيق والإجراء كوسائط وتعيد حالة جديدة. على سبيل المثال ، يمكن لمخفض المصادقة أن يأخذ حالة أولية لتطبيق ما في شكل كائن فارغ وإجراء يخبره أن المستخدم قد سجل الدخول وأعاد حالة تطبيق جديدة مع مستخدم قام بتسجيل الدخول.
الدوال الصرفة هي وظائف ليس لها أي آثار جانبية وسترجع نفس النتائج إذا تم تمرير نفس الوسيطات.
فيما يلي مثال على وظيفة نقية:
const add = (x, y) => x + y; add(2, 5);
يُرجع المثال أعلاه قيمة بناءً على المدخلات ، إذا قمت بتمرير 2
و 5
، فستحصل دائمًا على 7
، طالما أنه نفس الإدخال ، فلا شيء يؤثر على المخرجات التي تحصل عليها ، وهذا مثال على وظيفة خالصة.
يوجد أدناه مثال على وظيفة مخفض تأخذ في حالة وإجراء.
const initialState = {}; const cartReducer = (state = initialState, action) => { // Do something here }
دعنا نحدد المعلمتين اللتين يأخذهما المخفض ، state
action
.
حالة
الحالة هي البيانات التي يعمل بها المكون (المكونات) - فهي تحتفظ بالبيانات التي يتطلبها المكون وتحدد ما يعرضه المكون. بمجرد أن يتغير كائن state
، يعيد المكون تصيير. إذا كانت حالة التطبيق تتم إدارتها بواسطة Redux ، فإن المخفض هو المكان الذي تحدث فيه تغييرات الحالة.
عمل
الإجراء ، هو كائن يحتوي على حمولة المعلومات. هم مصدر المعلومات الوحيد لمتجر Redux ليتم تحديثه. تقوم مخفضات التحديث action.type
بناءً على قيمة نوع الإجراء. هنا سوف نحدد action.type
كـ ADD_TO_CART
.
وفقًا لوثائق Redux الرسمية ، فإن الإجراءات هي الأشياء الوحيدة التي تؤدي إلى حدوث تغييرات في تطبيق Redux ، فهي تحتوي على حمولة التغييرات في متجر التطبيقات. الإجراءات هي كائنات JavaScript تخبر Redux بنوع الإجراء المطلوب تنفيذه ، وعادة ما يتم تعريفها على أنها وظائف مثل تلك الموجودة أدناه:
const action = { type: 'ADD_TO_CART', payload: { product: 'margarine', quantity: 4 } }
الكود أعلاه هو قيمة payload
نموذجية تحتوي على ما يرسله المستخدم وسيتم استخدامه لتحديث حالة التطبيق. كما ترى أعلاه ، يحتوي كائن الإجراء على نوع الإجراء وكائن الحمولة الذي سيكون ضروريًا لتنفيذ هذا الإجراء المحدد.
تحديث الحالة باستخدام المخفضات
لتوضيح كيفية عمل المخفضات ، دعنا نلقي نظرة على عداد الأرقام أدناه:
const increaseAction = { type: 'INCREASE', }; const decreaseAction = { type: 'DECREASE' }; const countReducer = (state = 0, action) => { switch(action.type){ case INCREASE: return state + 1; case DECREASE : return state -1; default: return state; } };
في الكود أعلاه ، تعتبر increaseAction
العمل decreaseAction
الإجراء من الإجراءات المستخدمة في المخفض لتحديد ما يتم تحديث state
إليه. بعد ذلك ، لدينا وظيفة مخفض تسمى countReducer
، والتي تتخذ action
state
أولية تكون قيمتها 0
. إذا كانت قيمة action.type
هي INCREASE
، فإننا نعيد حالة جديدة تتزايد بمقدار 1 ، وإلا إذا كانت DECREASE
، فسيتم إرجاع حالة جديدة تنخفض بمقدار 1. في الحالات التي لا يقصد فيها أي من هذه الشروط ، نعود إلى state
.
تحديث الحالة باستخدام المخفضات: عامل الانتشار
لا يمكن تغيير الحالة بشكل مباشر ، لإنشاء الحالة أو تحديثها ، يمكننا استخدام عامل انتشار JavaScript للتأكد من أننا لا نغير قيمة الحالة مباشرة ولكن بدلاً من ذلك نعيد كائنًا جديدًا يحتوي على حالة تم تمريرها إليها و حمولة المستخدم.
const contactAction = { type: 'GET_CONTACT', payload: ['0801234567', '0901234567'] }; const initialState = { contacts: [], contact: {}, }; export default function (state = initialState, action) { switch (action.type) { case GET_CONTACTS: return { ...state, contacts: action.payload, }; default: return state; }
في الكود أعلاه ، نستخدم عامل انتشار للتأكد من أننا لا نغير قيمة الحالة مباشرة ، وبهذه الطريقة يمكننا إعادة كائن جديد مملوء بالحالة التي تم تمريرها إليه والحمولة التي تم إرسالها بواسطة المستعمل. باستخدام عامل انتشار ، يمكننا التأكد من بقاء الحالة كما هي حيث نضيف جميع العناصر الجديدة إليها وكذلك استبدال حقل جهات الاتصال في الحالة إذا كان موجودًا من قبل.
مخفضات التخفيض في العمل - عرض توضيحي
لفهم Redux Reducers وكيفية عملها بشكل أفضل ، سنقوم بتنفيذ تطبيق بسيط للبحث عن تفاصيل الفيلم ، ويمكن العثور على الكود وإصدار العمل هنا على Codesandbox. للبدء ، انتقل إلى جهازك الطرفي وقم بتهيئة تطبيق رد الفعل باستخدام الأمر أدناه:
create-react-app movie-detail-finder
بمجرد بدء مشروعنا ، دعنا بعد ذلك نثبت الحزم التي نحتاجها لتطبيقنا.
npm i axios reactstrap react-redux redux redux-thunk
بمجرد تثبيت الحزم ، لنبدأ خادم التطوير الخاص بنا باستخدام الأمر:
npm start
يجب أن يبدأ الأمر أعلاه خادم تطوير المشروع الخاص بنا في متصفحنا. بعد ذلك ، دعنا نفتح مشروعنا في محرر النصوص الذي نختاره ، داخل مجلد src
الخاص بالمشروع ، واحذف الملفات التالية: App.css
و App.test.js
و serviceWorker.js
و setupTests.js
. بعد ذلك ، دعنا نحذف جميع الأكواد التي تشير إلى الملفات المحذوفة على App.js
بالنسبة لهذا المشروع ، سنستخدم Open Movie Database API للحصول على معلومات الأفلام والمحتوى والصور الخاصة بنا لتطبيقنا ، وهنا رابط لواجهة برمجة التطبيقات ، ستحتاج إلى التسجيل والحصول على مفاتيح الوصول من أجل استخدامها لهذا الغرض التطبيق ، بمجرد الانتهاء ، دعنا نواصل تطبيقنا من خلال بناء المكونات.
مكونات تطبيقات البناء
أولاً ، داخل مجلد src
الخاص بنا في دليل المشروع الخاص بنا ، قم بإنشاء مجلد يسمى المكونات وداخل المجلد ، دعنا ننشئ مجلدين يسمى Movie
and Searchbar
، يجب أن يبدو المكون الخاص بنا مثل الصورة أدناه:
مكون فيلم البناء
لنقم ببناء مكون Movies
، والذي سيحدد هيكل تفاصيل الفيلم التي سنحصل عليها من واجهة برمجة التطبيقات الخاصة بنا. للقيام بذلك ، داخل مجلد Movies
الخاص بالمكون الخاص بنا ، قم بإنشاء ملف جديد Movie.js
، ثم أنشئ مكونًا قائمًا على الفئة لنتائج API ، دعنا نفعل ذلك أدناه.
import React, { Component } from 'react'; import { Card, CardImg, CardText, CardBody, ListGroup, ListGroupItem, Badge } from 'reactstrap'; import styles from './Movie.module.css'; class Movie extends Component{ render(){ if(this.props.movie){ return ( <div className={styles.Movie}> <h3 className="text-center my-4"> Movie Name: {this.props.movie.Title} </h3> <Card className="text-primary bg-dark"> <CardImg className={styles.Img} top src={this.props.movie.Poster} alt={this.props.movie.Title}/> <CardBody> <ListGroup className="bg-dark"> <ListGroupItem> <Badge color="primary">Actors:</Badge> {this.props.movie.Actors} </ListGroupItem> <ListGroupItem> <Badge color="primary">Genre:</Badge> {this.props.movie.Genre} </ListGroupItem> <ListGroupItem> <Badge color="primary">Year:</Badge> {this.props.movie.Year} </ListGroupItem> <ListGroupItem> <Badge color="primary">Writer(s):</Badge> {this.props.movie.Writer} </ListGroupItem> <ListGroupItem> <Badge color="primary">IMDB Rating:</Badge> {this.props.movie.imdbRating}/10 </ListGroupItem> </ListGroup> <CardText className="mt-3 text-white"> <Badge color="secondary">Plot:</Badge> {this.props.movie.Plot} </CardText> </CardBody> </Card> </div> ) } return null } } export default Movie;
في الكود أعلاه ، باستخدام مكونات من حزمة reactstrap
، يمكنك التحقق من التوثيق هنا. قمنا ببناء مكون بطاقة يتضمن اسم الفيلم ، والصورة ، والنوع ، والممثل ، والسنة ، وكاتب الفيلم ، والتصنيف ، والمؤامرة. لتسهيل تمرير البيانات من هذا المكون ، قمنا ببناء البيانات لتكون بمثابة دعائم لمكونات أخرى. بعد ذلك ، دعنا نبني مكون Searchbar
الخاص بنا.
بناء مكون شريط البحث الخاص بنا
Searchbar
مكون شريط البحث الخاص بنا على شريط بحث ومكون زر للبحث عن مكونات الفيلم ، دعنا نفعل ذلك أدناه:
import React from 'react'; import styles from './Searchbar.module.css'; import { connect } from 'react-redux'; import { fetchMovie } from '../../actions'; import Movie from '../Movie/Movie'; class Searchbar extends React.Component{ render(){ return( <div className={styles.Form}> <div> <form onSubmit={this.formHandler}> <input type="text" placeholder="Movie Title" onChange={e => this.setState({title: e.target.value})} value={this.state.title}/> <button type="submit">Search</button> </form> </div> <Movie movie={this.props.movie}/> </div> ) } }
في الكود أعلاه ، نقوم باستيراد connect
من react-redux
التي تُستخدم لتوصيل مكون React بمخزن Redux ، وتزويد المكون بمعلومات من المتجر ، كما يوفر الوظائف المستخدمة لإرسال الإجراءات إلى المتجر. بعد ذلك ، قمنا باستيراد مكون Movie
ووظيفة fetchMovie
من الإجراءات.
بعد ذلك ، لدينا علامة نموذج مع مربع إدخال لإدخال عناوين أفلامنا ، باستخدام خطاف setState
من React ، أضفنا حدث onChange
وقيمة ستحدد حالة title
إلى القيمة التي تم إدخالها في مربع الإدخال. لدينا علامة button
للبحث عن عناوين الأفلام وباستخدام مكون Movie
الذي قمنا باستيراده ، قمنا بتمرير خصائص المكون props
إلى نتيجة البحث.
التالي بالنسبة لنا هو كتابة وظيفة لإرسال عنوان الفيلم الخاص بنا إلى واجهة برمجة التطبيقات من أجل إرسال النتائج إلينا ، نحتاج أيضًا إلى تعيين الحالة الأولية للتطبيق. لنفعل ذلك أدناه.
class Searchbar extends React.Component{ state = { title: '' } formHandler = (event) => { event.preventDefault(); this.props.fetchMovie(this.state.title); this.setState({title: ''}); }
هنا ، قمنا بتعيين الحالة الأولية للتطبيق على سلاسل فارغة ، وقمنا بإنشاء دالة formHandler
التي تأخذ معلمة حدث وتمرير وظيفة fetchMovie
من الإجراء وتعيين العنوان كحالة جديدة للتطبيق. لإكمال تطبيقنا ، دعنا نصدر هذا المكون باستخدام خاصية الاتصال من react-redux
، للقيام بذلك ، سنستخدم خاصية رد الفعل redux mapToStateProps
لتحديد جزء البيانات الذي يحتاجه مكوننا ، يمكنك معرفة المزيد حول mapToStateProps
هنا.
const mapStateToProps = (state) => { return { movie: state.movie } } export default connect(mapStateToProps, { fetchMovie })(Searchbar)
دعنا نضيف أنماطًا إلى نموذجنا عن طريق إنشاء ملف Searchbar.module.css
وإضافة الأنماط أدناه:
.Form{ margin: 3rem auto; width: 80%; height: 100%; } input{ display: block; height: 45px; border: none; width: 100%; border-radius: 0.5rem; outline: none; padding: 0 1rem; } input:focus, select:focus{ border: 2px rgb(16, 204, 179) solid; } .Form button{ display: block; background: rgb(16, 204, 179); padding: 0.7rem; border-radius: 0.5rem; width: 20%; margin-top: 0.7rem; color: #FFF; border: none; text-decoration: none; transition: all 0.5s; } button:hover{ opacity: 0.6; } @media(max-width: 700px){ input{ height: 40px; padding: 0 1rem; } .Form button{ width: 40%; padding: 0.6rem; } }
بمجرد قيامنا بما ورد أعلاه ، يجب أن يبدو مكون شريط البحث الخاص بنا مشابهًا للصورة أدناه:
خلق إجراءات للتطبيق
في هذا المكون ، سنقوم بإعداد إجراءات Redux لتطبيقنا ، أولاً ، داخل دليل src
، أنشئ مجلدًا باسم actions
وداخل المجلد ، سننشئ ملف index.js
. سننشئ هنا دالة fetchMovie
تأخذ معلمة العنوان ، وتجلب الفيلم من واجهة برمجة التطبيقات باستخدام Axios. لنفعل هذا أدناه:
import axios from 'axios'; export const fetchMovie = (title) => async (dispatch) => { const response = await axios.get( `https://cors-anywhere.herokuapp.com/https://www.omdbapi.com/?t=${title}&apikey=APIKEY`); dispatch({ type: 'FETCH_MOVIE', payload: response.data }) }
في الكود أعلاه ، قمنا باستيراد fetchMovie
axios
معلمة title
باستخدام غير متزامن / انتظار حتى نتمكن من تقديم طلب إلى خادم واجهة برمجة التطبيقات. لدينا وظيفة dispatch
ترسل إلى Redux كائن الإجراء الذي تم تمريره إليه. مما لدينا أعلاه ، نرسل إجراءً من النوع FETCH_MOVIE
والحمولة التي تحتوي على الاستجابة التي حصلنا عليها من واجهة برمجة التطبيقات.
ملاحظة: سيتم استبدال apikey
في الطلب بـ apikey
الخاص بك بعد التسجيل في OmdbAPI .
إنشاء مخفضات التطبيق
في هذا القسم ، سنقوم بإنشاء مخفضات لتطبيقنا.
const fetchMovieReducer = (state = null, action) => { switch(action.type){ case 'FETCH_MOVIE': return action.payload; default: return state; } } const rootReducer = (state, action) => { return { movie: fetchMovieReducer(state, action) } } export default rootReducer;
في الكود أعلاه ، أنشأنا fetchMovieReducer
الذي يأخذ حالة افتراضية null
ومعلمة action
، باستخدام عامل تشغيل ، بالنسبة للحالة FETCH_MOVIE
، سنعيد قيمة action.payload
وهو الفيلم الذي حصلنا عليه من واجهة برمجة التطبيقات. إذا لم يكن الإجراء الذي حاولنا تنفيذه في المخفض ، فسنرجع حالتنا الافتراضية.
بعد ذلك ، أنشأنا وظيفة rootReducer
التي ستقبل الحالة الحالية وإجراءً كمدخلات وإرجاع fetchMovieReducer
.
نضعها معا
في هذا القسم ، انتهينا من تطبيقنا بإنشاء متجر redux في index.js
، لنفعل ذلك أدناه:
import React from 'react'; import ReactDOM from 'react-dom'; import { Provider } from 'react-redux'; import { createStore, applyMiddleware } from 'redux'; import thunk from 'redux-thunk'; import App from './App'; import 'bootstrap/dist/css/bootstrap.min.css'; import './index.css'; import reducers from './reducers'; const store = createStore(reducers, applyMiddleware(thunk)) ReactDOM.render( <Provider store={store}> <> <App/> </> </Provider>, document.getElementById('root') )
في الكود أعلاه ، أنشأنا store
التطبيقات باستخدام طريقة createStore
بتمرير المخفض الذي أنشأناه والبرمجيات الوسيطة. Middlewares هي الأدوات الإضافية التي تسمح لنا بتحسين وظائف Redux. نحن هنا نستخدم البرمجيات الوسيطة Redux Thunk باستخدام applyMiddleware
. تعد البرامج الوسيطة Redux Thunk ضرورية لمتجرنا لإجراء تحديثات غير متزامنة. هذا ضروري لأنه افتراضيًا ، يقوم Redux بتحديث المتجر بشكل متزامن.
للتأكد من أن تطبيقنا يعرف المتجر الدقيق الذي يجب استخدامه ، قمنا بلف تطبيقنا في مكون Provider
وقمنا بتمرير المتجر كدعم ، من خلال القيام بذلك ، يمكن للمكونات الأخرى في تطبيقنا الاتصال ومشاركة المعلومات مع المتجر.
دعنا نضيف القليل من النمط إلى ملف index.css
بنا.
*{ margin: 0; padding: 0; box-sizing: border-box; } body{ background: rgb(15, 10, 34); color: #FFF; height: 100vh; max-width: 100%; }
تقديم واختبار مكتشف تفاصيل الفيلم
في هذا القسم ، سننهي طلبنا من خلال تقديم تطبيقنا في App.js
، للقيام بذلك ، دعنا ننشئ مكونًا قائمًا على الفئة يسمى App
ونبدأ في تهيئة شريط البحث وحقل الإدخال.
import React from 'react'; import Searchbar from './components/Searchbar/Searchbar'; import styles from './App.module.css'; class App extends React.Component{ render(){ return( <div className={styles.App}> <h1 className={styles.Title}>Movies Search App</h1> <Searchbar/> </div> ) } } export default App;
هنا ، أنشأنا مكونًا يستند إلى فئة التطبيقات باستخدام h1
يشير إلى تطبيق Movie Search Searchbar
مكون شريط البحث الخاص بنا. يجب أن يظهر تطبيقنا بالصورة أدناه:
يتوفر عرض توضيحي عملي على Codesandbox.
خاتمة
تعد المخفضات جزءًا مهمًا من إدارة حالة Redux ، حيث يمكننا باستخدام المخفضات كتابة وظائف خالصة لتحديث مناطق معينة من تطبيقات Redux دون آثار جانبية. لقد تعلمنا أساسيات مخفضات Redux ، واستخداماتها ، والمفهوم الأساسي للمخفضات ، والحالة ، والحجج.
يمكنك المضي قدمًا في هذا من خلال الاطلاع على الوثائق الخاصة بمخفضات Redux هنا. يمكنك المضي قدمًا في هذا الأمر وبناء المزيد على مخفضات Redux ، اسمح لي بمعرفة ما تقوم ببنائه.
موارد
- توثيق React-Redux
- وثائق الاستعادة
-
connect()
وظيفة -
applyMiddleware
وظيفة