تحياتي ، اليوم سأتحدث معك حول كيفية تنظيم المخفض. ولتحديد من أين بدأت وماذا أتيت.
لذلك ، هناك معيار معين لتنظيم المخفض ويبدو كما يلي:
export default function someReducer(state = initialState, action) { switch (action.type) { case 'SOME_REDUCER_LABEL': return action.data || {}; default: return state; } }
كل شيء بسيط وواضح هنا ، لكن بعد أن عملت قليلاً مع هذه الإنشاءات ، أدركت أن هذه الطريقة بها عدد من الصعوبات.
- يجب تخزين العلامات بطريقة أو بأخرى ، لأنها بدأت في الزحف على طول المشروع والزحف إلى أبعد من وحدات التحكم.
- يجب أن تكون الملصقات فريدة من نوعها ، لأنه بخلاف ذلك قد يكون هناك تقاطع مع مخفضات أخرى
- تم إنفاق معظم الوقت عند العمل مع هذا الهيكل على تنظيم الكود بدلاً من معالجة البيانات الواردة
- وعندما يكون هناك الكثير من التسميات في المخفض ، تصبح الشفرة قذرة ويصعب قراءتها ، ولم يفسح لي مساحة الاسم العامة.
في الوقت نفسه تقريبًا ، بدأنا في استخدام الساجاس لمعالجة الآثار الجانبية. هذا سمح لنا بتسهيل التواصل مع جانب الخادم بشكل كبير دون استخدام عمليات الاسترجاعات.
الآن كان علينا أن ندع الملحمة تعرف المخفض الذي يجب استدعاؤه بعد التأثير الجانبي.
الخيار الأكثر منطقية الذي وجدته هو صنع منشئ الحركة.
وقد بدأ الكود السابق في الشكل التالي:
import { FetchSaga } from '../../helpers/sagasHelpers'; const SOME_REDUCER_LABEL = 'SOME_REDUCER_LABEL'; export const someReducerLabelActionCreator = FetchSaga.bind(this, SOME_REDUCER_LABEL); export default function someReducer(state = initialState, action) { switch (action.type) { case SOME_REDUCER_LABEL: return action.data || {}; default: return state; } }
FetchSaga هي وظيفة منشئ التصرفات (يشار إليها فيما بعد باسم منشئ التصرفات) بالنسبة إلى الملحمة التي تطلب البيانات من الخادم وترسلها إلى المخفض ، والتي تم نقل التسمية الخاصة بها إلى الوظيفة في مرحلة التهيئة (SOME_REDUCER_LABEL).
الآن ، تم تصدير ملصقات المخفض إما من المخفض ، أو تم تصدير مُنشئ الإجراء من المخفض لكل من الملحمة والمعيار العادي. علاوة على ذلك ، تم إنشاء مثل هذا المعالج لكل تسمية. لم يؤد ذلك إلا إلى إضافة صداع ، لأنني بمجرد فتح المخفض ، أحسب 10 ثوابت من الملصقات المحددة ، ثم عدد قليل من الدعوات لمبدعي تصرفات مختلفة من أجل sagas ومن ثم وظيفة معالجة حالة المخفض ، بدا الأمر كما يلي
import { FetchSaga } from '../../helpers/sagasHelpers'; const SOME_REDUCER_LABEL1 = 'SOME_REDUCER_LABEL1'; .... const SOME_REDUCER_LABEL10 = 'SOME_REDUCER_LABEL10'; export const someReducerLabelActionCreator1 = FetchSaga.bind(this, SOME_REDUCER_LABEL1); ..... export const someReducerLabelActionCreator10 = FetchSaga.bind(this, SOME_REDUCER_LABEL10); export default function someReducer(state = initialState, action) { switch (action.type) { case SOME_REDUCER_LABEL: return action.data || {}; case SOME_REDUCER_LABEL1: return action.data || {}; case SOME_REDUCER_LABEL2: return action.data || {}; case SOME_REDUCER_LABEL3: return action.data || {}; .... default: return state; } }
عند استيراد كل هذه الإجراءات إلى وحدة التحكم ، تم تضخيم هذا الإجراء أيضًا كثيرًا. وحصلت في الطريق.
بعد أن نظرت إلى العديد من المخفضات ، أحسب أننا نكتب الكثير من التعليمات البرمجية التي لا تتغير أبداً. بالإضافة إلى ذلك ، يجب علينا التأكد من إرسال الحالة المستنسخة إلى المكون.
ثم كان لدي فكرة لتوحيد المخفض. المهام قبله لم تكن صعبة.
- تحقق من الإجراء الوارد وأعد الحالة القديمة إذا لم يكن الإجراء مخصصًا للمخفض الحالي أو استنساخ تلقائيًا وقم بتمريره إلى طريقة المعالج ، مما يؤدي إلى تغيير الحالة وإعادته إلى المكون.
- يجب أن تتوقف عن استخدام الملصقات ، بدلاً من ذلك ، يجب أن تتلقى وحدة التحكم كائنًا يحتوي على جميع منشئي الإجراءات للمخفض الذي نحن مهتمون به.
وبالتالي ، بعد استيراد هذه المجموعة مرة واحدة ، أستطيع أن أنقل خلالها أي عدد من منشئي الإجراءات لإرسال وظائف من المخفض إلى وحدة التحكم دون الحاجة إلى إعادة الاستيراد - بدلاً من استخدام حالة تبديل أخرق مع مساحة اسم شائعة يستخدمها linter ، أريد أن يكون لديّ طريقة منفصلة لكل إجراء ، يتم فيها نقل الحالة المستنسخة للمخفف والإجراء نفسه
- سيكون من الجميل أن تكون قادرًا على أن يرث مخفضًا جديدًا من المخفض. في حالة تكرار المنطق ، ولكن على سبيل المثال لمجموعة مختلفة من التسميات.
بدت الفكرة قابلة للحياة بالنسبة لي وقررت أن أحاول تنفيذها.
إليك ما بدأه المخفض المتوسط في الظهور الآن
// , reducer' import stdReducerClass from '../../../helpers/reducer_helpers/stdReducer'; class SomeReducer extends stdReducerClass { constructor() { super(); /** reducer'. reducer action, */ this.prefix = 'SOME_REDUCER__'; } /** , reducer - type - , . - , action creator, SOME_REDUCE__FETCH. type action creator someReduceInstActions - method - , action, - sagas - , , . , action creator , SOME_REDUCE__FETCH, , , reducer . */ config = () => [ { type: 'fetch', method: this.fetch, saga: 'fetch' }, { type: 'update', method: this.update }, ]; // action creators init = () => this.subscribeReduceOnActions(this.config()); // , fetch = (clone, action) => { // return clone; }; // , update = (clone, action) => { // return clone; }; } const someReducerInst = new SomeReducer(); someReducerInst.init(); // action creators config // action creator export const someReducerInstActions = someReducerInst.getActionCreators(); // . checkActionForState Action , reducer' export default someReducerInst.checkActionForState;
stdReducerClass من الداخل على النحو التالي
import { cloneDeep } from 'lodash'; // lodash // , import { FetchSaga } from '../helpers/sagasHelpers/actions'; export default class StdReducer { _actions = {}; actionCreators = {}; /** UNIQUE PREFIX BLOCK START */ /** , . , , , reducer action */ uniquePrefix = ''; set prefix(value) { const lowedValue = value ? value.toLowerCase() : ''; this.uniquePrefix = lowedValue; } get prefix() { return this.uniquePrefix; } /** INITIAL STATE BLOCK START */ /** initialState reducer'. */ initialStateValues = {}; set initialState(value) { this.initialStateValues = value; } get initialState() { return this.initialStateValues; } /** PUBLIC BLOCK START */ /** * init() . , Config, action creator _subscribeAction * actionsConfig - , {type, method, saga?} , action creator */ subscribeReducerOnActions = actionsConfig => actionsConfig.forEach(this._subscribeAction); /** _subscribeAction, , type. , reducer , action. */ _subscribeAction = (action) => { const type = action.type.toLowerCase(); this._actions[type] = action.method; // this.actionCreators[type] = this._subscribeActionCreator(type, action.saga); // action creator } /** _subscribeActionCreator - , action creator - saga , - fetch , type , , action creator, , SOME_Reducer__, FETCH, SOME_Reducer__FETCH, action creator */ _subscribeActionCreator = (type, creatorType) => { const label = (this.prefix + type).toUpperCase(); switch (creatorType) { case 'fetch': return this._getFetchSaga(label); default: return this._getActionCreator(label); } } /** _getFetchSaga - , */ _getFetchSaga = label => FetchSaga.bind(this, label); /** _getActionCreator - action creator, , , . */ _getActionCreator = label => (params = {}) => ({ type: label, ...params }); /** , playload. action , */ checkActionForState = (state = this.initialState || {}, action) => { if (!action.type) return state; const type = action.type.toLowerCase(); const prefix = this.prefix; , , . const internalType = type.replace(prefix, ''); // if (this._actions[internalType]) { // - const clone = cloneDeep(state); // , , action , // return this._actions[internalType](clone, action); } // , action . return state; } /** action creator, reducer */ getActionCreators = () => this.actionCreators; }
كيف تبدو في وحدة التحكم؟ و كذلك
import { someReducerInstActions } from '../../../SomeReducer.js' const mapDispatchToProps = dispatch => ({ doSoAction: (params) => dispatch(someReducerInstActions.fetch(url, params)), doSoAction1: (value, block) => dispatch(someReducerInstActions.update({value, block})), });
لذلك ، ماذا لدينا نتيجة:
- تخلصت من تراكم العلامات
- تخلصت من مجموعة من الواردات في وحدة التحكم
- إزالة حالة التبديل
- لقد تغلبوا على الساجا مرة واحدة والآن يمكننا توسيع مجموعتهم في مكان واحد ، والتأكد من أن جميع الورثة سيتلقون معالجات إضافية للأثر الجانبي تلقائيًا
- حصلنا على فرصة الميراث من المخفضات ، في حالة وجود منطق ذي صلة (في هذه اللحظة لم يكن هذا مفيدًا لي أبدًا))
- لقد حولوا مسؤولية الاستنساخ من المطور إلى فصل من شأنه أن يتذكر بالتأكيد القيام بذلك.
- أقل الروتينية عند إنشاء المخفض
- كل طريقة لها مساحة اسم معزولة
حاولت وصف كل شيء بأكبر قدر ممكن من التفصيل =) عذرا ، إذا كان الأمر مرتبكًا ، فإن Chukchi ليس كاتباً. آمل أن تكون تجربتي مفيدة لشخص ما.
→ يمكن رؤية المثال الحالي هنا
شكرا للقراءة!
محدث: الأخطاء الثابتة. كتب في الليل ، وقراءة سيئة. شكرا لتوجيه الشكر لهم بدقة =)