
يوم جيد ، خابروفسك!
أريد أن أتحدث عن الطريقة التي تعلمت بها مؤخرًا بعض "الخطافات" في React. ظهرت مؤخرًا نسبيًا ، في الإصدار [16.8.0] المؤرخ 6 فبراير 2019 (والذي ، وفقًا لسرعات التطوير لـ FrontEnd ، بالفعل منذ زمن طويل جدًا)
بعد قراءة الوثائق ، ركزت على خطاف useReducer وسألت نفسي على الفور السؤال: "هذا الشيء يمكن أن يحل محل Redux بالكامل؟" قضيت عدة أمسيات في التجارب وأريد الآن مشاركة النتائج واستنتاجاتي.
هل أحتاج إلى استبدال Redux مع useContext + useReducer؟
لفارغ الصبر - النتائج على الفور
الايجابيات:
- يمكنك استخدام الخطافات (useContext + useReducer) بدلاً من Redux في التطبيقات الصغيرة (حيث لا توجد حاجة إلى مخفضات كبيرة مدمجة). في هذه الحالة ، قد يكون Redux بالفعل زائداً عن الحاجة.
سلبيات:
- لقد تم بالفعل كتابة كمية كبيرة من التعليمات البرمجية على مجموعة من React + Redux ولا يبدو أنه من المستحسن إعادة كتابتها إلى خطافات (useContext + useReducer) ، على الأقل حتى الآن.
- Redux هي مكتبة مثبتة ، والسنانير هي ابتكار ، وقد تتغير واجهاتها وسلوكها في المستقبل.
- من أجل جعل استخدام useContext + useReducer مناسبًا جدًا ، سيتعين عليك كتابة بعض الدراجات.
الاستنتاجات هي الرأي الشخصي للمؤلف ولا تدعي أنها حقيقة غير مشروطة - إذا لم توافق ، فسأكون سعيدًا لرؤية انتقاداتك البناءة في التعليقات.
دعنا نحاول معرفة ذلك
لنبدأ بمثال بسيط.
(reducer.js)
import React from "react"; export const ContextApp = React.createContext(); export const initialState = { app: { test: 'test_context' } }; export const testReducer = (state, action) => { switch(action.type) { case 'test_update': return { ...state, ...action.payload }; default: return state } };
حتى الآن ، يبدو المخفض لدينا تمامًا كما في Redux
(app.js)
import React, {useReducer} from 'react' import {ContextApp, initialState, testReducer} from "./reducer.js"; import {IndexComponent} from "./IndexComponent.js" export const App = () => {
(IndexComponent.js)
import React, {useContext} from "react"; import {ContextApp} from "./reducer.js"; export function IndexComponent() {
هذا هو أبسط مثال على أننا ببساطة تحديث إرسال بيانات جديدة إلى المخفض المسطح (بدون تداخل)
من الناحية النظرية ، يمكنك حتى محاولة كتابة مثل هذا:
(reducer.js)
... export const testReducer = (state, data) => { return { ...state, ...data } ...
(IndexComponent.js)
... return (
إذا لم يكن لدينا تطبيق كبير وبسيط (وهو نادرًا ما يكون هذا هو الواقع في الواقع) ، فلا يمكنك استخدام كتابة وإدارة تحديثات المخفض دائمًا مباشرة من الإجراء. بالمناسبة ، على حساب التحديثات ، في هذه الحالة كتبنا فقط بيانات جديدة في المخفض ، ولكن ماذا لو كان علينا تغيير قيمة واحدة في شجرة مع عدة مستويات من التعشيش؟
أكثر تعقيدا الآن
لنلقِ نظرة على المثال التالي:
(IndexComponent.js)
... return (
(reducer.js)
... export const initialState = { tree_1: { tree_2_1: { tree_3_1: 'tree_3_1', tree_3_2: 'tree_3_2' }, tree_2_2: { tree_3_3: 'tree_3_3', tree_3_4: 'tree_3_4' } } }; export const testReducer = (state, callback) => {
حسنًا ، اكتشفنا تحديث الشجرة أيضًا. رغم أنه في هذه الحالة ، من الأفضل بالفعل العودة إلى استخدام الأنواع الموجودة داخل testReducer وتحديث الشجرة وفقًا لنوع معين من الإجراءات. كل شيء يشبه في Redux ، فقط الحزمة الناتجة أصغر قليلاً [8].
عمليات غير متزامنة والإرسال
ولكن هل كل شيء على ما يرام؟ ماذا يحدث إذا ذهبنا لاستخدام عمليات غير متزامنة؟
للقيام بذلك ، سيتعين علينا تحديد الإرسال الخاص بنا. لنجربها!
(action.js)
export const actions = { sendToServer: function ({dataForServer}) {
(IndexComponent.js)
const [state, _dispatch] = useReducer(AppReducer, AppInitialState);
يبدو أن كل شيء على ما يرام أيضًا ، ولكن لدينا الآن الكثير من عمليات الاسترجاعات المتداخلة ، وهي ليست رائعة جدًا ، إذا كنا نريد فقط تغيير الحالة دون إنشاء وظيفة إجراء ، فسوف يتعين علينا كتابة بنية من هذا النوع:
(IndexComponent.js)
... dispatch( (dispatch) => dispatch(state => { return { {dataForServer: 'data'} } }) ) ...
اتضح شيء مخيف ، أليس كذلك؟ للحصول على تحديث بسيط للبيانات ، أرغب بشدة في كتابة شيء مثل هذا:
(IndexComponent.js)
... dispatch({dataForServer: 'data'}) ...
للقيام بذلك ، سيتعين عليك تغيير الخادم الوكيل لوظيفة الإرسال التي أنشأناها مسبقًا
(IndexComponent.js)
const [state, _dispatch] = useReducer(AppReducer, AppInitialState);
الآن يمكننا تمرير كل من وظيفة الحركة وكائن بسيط لإرساله.
ولكن! مع النقل البسيط للكائن ، يجب أن تكون حذرًا ، فقد يتم إغراءك للقيام بذلك:
(IndexComponent.js)
... dispatch({ tree: {
لماذا هذا المثال سيء؟ بحقيقة أنه بحلول وقت معالجة هذا الإرسال ، كان من الممكن تحديث الحالة من خلال إرسال آخر ، لكن هذه التغييرات لم تصل بعد إلى مكوننا ، وفي الواقع نحن نستخدم مثيل حالة قديم سيحل محل كل شيء بالبيانات القديمة.
لهذا السبب ، فإن مثل هذه الطريقة تصبح مناسبة في أي مكان ، فقط لتحديث المخفضات المسطحة التي لا يوجد فيها تداخل ولا تحتاج إلى استخدام الحالة لتحديث الكائنات المتداخلة. في الواقع ، نادراً ما تكون أجهزة التروس مسطحة تمامًا ، لذا فإنني أنصحك بعدم استخدام هذه الطريقة على الإطلاق وتحديث البيانات فقط من خلال الإجراءات.
(action.js)
...
الاستنتاجات:
- لقد كانت تجربة مثيرة للاهتمام ، وعززت معرفتي الأكاديمية وتعلمت ميزات جديدة من رد الفعل
- لن أستخدم هذا النهج في الإنتاج (على الأقل في الأشهر الستة المقبلة). للأسباب الموضحة أعلاه (هذه ميزة جديدة ، و Redux هي أداة مجربة وموثوقة) + ليس لدي أي مشاكل في الأداء لمطاردتها بعد الألف من الثانية التي يمكنك الفوز بها عن طريق التخلي عن المحرر [8]
يسعدني أن أعرف ، في التعليقات ، رأي الزملاء من الجزء الأمامي من Habrosobschestva لدينا!
المراجع: