في هذا المنشور سوف نتطرق إلى إجراءات الكتابة والمخفض. للبدء ، فكر في "تدفق" نموذجي ، ننفذ فيه العمليات التالية (علاوة على ذلك ، نعيد صياغة كل شيء حتى يتوافق رمزنا مع مبادئ SOLID).
1. إنشاء ملف مع الثوابت (هنا نحفظ أسماء أنواع الإجراءات)
export const REQUEST_DATA_PENDING = "REQUEST_DATA_PENDING"; export const REQUEST_DATA_SUCCESS = "REQUEST_DATA_SUCCESS"; export const REQUEST_DATA_FAILED = "REQUEST_DATA_FAILED"; export const PROFILES_PER_PAGE = "PROFILES_PER_PAGE"; export const CURRENT_PAGE = "CURRENT_PAGE";
2. قم بإنشاء ملف حيث نصف الإجراءات (هنا نقوم بتقديم طلب لحسابات المستخدمين والصفحات). أيضًا في المثال تم استخدام redux-thunk (كذلك سنرفض تبعيات مماثلة):
export const requestBigDataAction = () => (dispatch) => { fetchingData(dispatch, BIG_DATA_URL, 50); } export const changeCurrentPAGE = (page) => ({ type: CURRENT_PAGE, payload: page }) function fetchingData(dispatch, url, profilesPerPage) { dispatch({type: REQUEST_DATA_PENDING}); fetch(url) .then((res) => { if(res.status !== 200) { throw new Error (res.status); } else { return res.json(); } }) .then((data) => {dispatch({type: REQUEST_DATA_SUCCESS, payload: data})}) .then(() => dispatch({type: PROFILES_PER_PAGE, payload: profilesPerPage})) .catch((err) => dispatch({type: REQUEST_DATA_FAILED, payload: ` . ${err.message}`})); }
3. نكتب المخفض
import { REQUEST_DATA_PENDING, REQUEST_DATA_SUCCESS, REQUEST_DATA_FAILED, PROFILES_PER_PAGE, CURRENT_PAGE } from '../constants/constants'; const initialState = { isPending: false, buffer: [], data: [], error: "", page: 0, profilesPerPage: 0, detailedProfile: {} } export const MainReducer = (state = initialState, action = {}) => { switch(action.type) { case REQUEST_DATA_PENDING: return Object.assign({}, state, {isPending: true}); case REQUEST_DATA_SUCCESS: return Object.assign({}, state, {page : 0, isPending: false, data: action.payload, error: "", detailedProfile: {}, buffer: action.payload}); case REQUEST_DATA_FAILED: return Object.assign({}, initialState, {error: action.payload}); case PROFILES_PER_PAGE: return Object.assign({}, state, {profilesPerPage: action.payload}); case CURRENT_PAGE: return Object.assign({}, state, {page: action.payload}); default: return state; } }
4. تكوين المتجر (استخدام الوسيطة thunkMiddleware)
import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import App from './App'; import {createStore, applyMiddleware} from 'redux'; import {Provider} from 'react-redux'; import thunkMiddleware from 'redux-thunk'; import {MainReducer} from './reducers/mainReducer'; const store = createStore(MainReducer, applyMiddleware(thunkMiddleware)); ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('root'));
5. قم بتوصيل المكون لإعادة
const mapDispatchToProps = (dispatch)=>{ return { onRequestBigData: (event) =>{ dispatch(requestBigDataAction()); } } };
ربط أزرار ترقيم الصفحات لإعادة
const mapDispatchToProps = (dispatch)=>{ return { onChangePage: (page) =>{ dispatch(changeCurrentPAGE(page)); } } };
المشكلة: المخفض الخاص بنا عبارة عن بيان تبديل كبير ، لذلك ، عند إضافة إجراء جديد ، أو تغيير سلوكه ، نحتاج إلى تغيير المخفض الخاص بنا ، الذي ينتهك مبادئ SOlid (مبدأ المسؤولية الفردية ومبدأ الانفتاح / التقارب).
الحل: سوف يساعدنا تعدد الأشكال. أضف إلى كل إجراء طريقة التنفيذ التي ستطبق التحديث وتعيد الحالة المحدثة. ثم سوف تأخذ المخفض لدينا النموذج
export const MainReducer = (state = initialState, action) => { if(typeof action.execute === 'function') return action.execute(state); return state; };
الآن عند إضافة إجراء جديد ، لا نحتاج إلى تغيير المخفض ، ولا يتحول إلى وحش ضخم.
بعد ذلك ، التخلي عن thux-redux وإعادة كتابة الإجراءات
import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import App from './App'; import {createStore} from 'redux'; import {Provider} from 'react-redux';
انتقل إلى المكون المتصل ، الذي يكون إجراءه غير متزامن (يجب تصحيحه قليلاً)
const mapDispatchToProps = (dispatch)=>{ return { onRequestBigData: (event) =>{ requestBigDataAction(dispatch); }, } };
والانتقال إلى الإجراءات نفسها وإضافة طريقة التنفيذ إليها
const type = 'bla-bla'; const requestDataPending = {execute: state => ({...state, isPending: true}), type}; const requestDataSuccess = payload => ({ execute: function (state) { return ({...state, page : 0, isPending: false, data: payload, error: "", detailedProfile: {}, buffer: payload}) }, type}) const profilesPerPageAction = profilesPerPage => ({ execute: state => ({...state, profilesPerPage: profilesPerPage}), type }); const requestDataFailed = errMsg => state => ({...state, error: ` . ${errMsg}`}); function fetchingData(dispatch, url, profilesPerPage) { dispatch(requestDataPending); fetch(url) .then((res) => { if(res.status !== 200) { throw new Error (res.status); } else { return res.json(); } }) .then((data) => {dispatch(requestDataSuccess(data))}) .then(() => dispatch(profilesPerPageAction(profilesPerPage))) .catch((err) => dispatch(requestDataFailed(err.message))); } export const requestBigDataAction = (dispatch) => { fetchingData(dispatch, BIG_DATA_URL, 50); } export const changeCurrentPAGE = page => ({ type, execute: state => ({...state, page}) })
ملاحظة: خاصية الكتابة مطلوبة (إذا لم تقم بإضافتها ، فسيتم طرح استثناء). ولكن بالنسبة لنا لا يهم على الإطلاق. لهذا السبب لم نعد بحاجة إلى ملف منفصل يسرد أنواع الإجراءات.
ملاحظة: في هذه المقالة ، طبقنا مبادئ SRP و OCP ، تعدد الأشكال ، تخلينا عن مكتبة الطرف الثالث وجعلنا كودنا أكثر نظافة ويمكن صيانته.