javascript شرح - لماذا استخدام Redux عبر Facebook Flux؟




ماهو ترجمة (6)

في Quora ، يقول شخص ما :

بادئ ذي بدء ، فمن الممكن تماما لكتابة التطبيقات مع React دون Flux.

كما يوضح هذا المخطط المرئي الذي قمت بإنشائه عرضًا سريعًا لكليهما ، على الأرجح إجابة سريعة للأشخاص الذين لا يرغبون في قراءة التفسير الكامل:

ولكن إذا كنت لا تزال مهتمًا بمعرفة المزيد ، فاقرأ.

أعتقد أنك يجب أن تبدأ بـ React نقية ، ثم تعلم Redux و Flux. بعد أن يكون لديك بعض الخبرة الحقيقية مع React ، سترى ما إذا كان Redux مفيدًا لك أم لا.

ربما ستشعر أن Redux مناسب تمامًا لتطبيقك وربما ستكتشف أن Redux يحاول حل مشكلة لا تعاني منها حقًا.

إذا بدأت مباشرة مع Redux ، فقد ينتهي بك الأمر برمز مفرغ هندسيًا ورمزًا أصعب للمحافظة عليه ومع المزيد من الأخطاء وبدون استخدام Redux.

من مستندات Redux :

التحفيز
نظرًا لأن متطلبات تطبيقات أحادية الصفحة لجافا سكريبت أصبحت معقدة بشكل متزايد ، يجب أن يتولى كودنا إدارة حالة أكثر من أي وقت مضى. يمكن أن تتضمن هذه الحالة استجابات الخادم والبيانات المخزنة مؤقتًا ، بالإضافة إلى البيانات التي تم إنشاؤها محليًا والتي لم تستمر حتى الآن في الخادم. تتزايد حالة واجهة المستخدم أيضًا من حيث التعقيد ، نظرًا لأننا نحتاج إلى إدارة المسارات النشطة وعلامات التبويب المحددة والمغنيات وعناصر التحكم في الفواصل ، وما إلى ذلك.

إدارة هذه الحالة المتغيرة أمر صعب. إذا كان بإمكان النموذج تحديث نموذج آخر ، فيمكن حينئذٍ لطريقة العرض تحديث نموذج ، يقوم بتحديث نموذج آخر ، وهذا بدوره قد يتسبب في تحديث آخر. في مرحلة ما ، لم تعد تفهم ما يحدث في تطبيقك حيث فقدت السيطرة على متى ولماذا وكيف حاله. عندما يكون النظام معتمًا وغير محدد ، فمن الصعب إعادة إنتاج الخلل أو إضافة ميزات جديدة.

كما لو أن هذا لم يكن سيئًا بما فيه الكفاية ، ففكر في المتطلبات الجديدة التي أصبحت شائعة في تطوير المنتجات الأمامية. كمطورين ، من المتوقع أن نتعامل مع تحديثات متفائلة ، وعرض من جانب الخادم ، وجلب البيانات قبل إجراء عمليات نقل المسارات ، وما إلى ذلك. إننا نجد أنفسنا نحاول إدارة تعقيد لم نتعامل معه من قبل ، ونحن نطرح السؤال حتمًا: هل حان الوقت للتخلي؟ الجواب لا.

من الصعب التعامل مع هذا التعقيد حيث أننا نمزج مفهومين من الصعب جدًا على العقل البشري التفكير فيه: الطفرة وعدم التزامن. أنا أسميهم Mentos و Coke. كلاهما يمكن أن يكونا رائعين عند الفصل بينهما ، لكنهما معاً يخلقان فوضى. تحاول المكتبات مثل React حل هذه المشكلة في طبقة العرض عن طريق إزالة كل من asynchrony و direct DOM manipulation. ومع ذلك ، فإن إدارة حالة بياناتك متروك لك. هذا هو المكان الذي يأتي في Redux.

على خطى Flux و CQRS و Sourcing Event ، يحاول Redux جعل طفرات الدولة متوقعة عن طريق فرض قيود معينة على كيفية ووقت حدوث التحديثات. تنعكس هذه القيود في المبادئ الثلاثة لـ Redux.

أيضًا من مستندات Redux :

المفاهيم الأساسية
Redux نفسها بسيطة جدا.

تخيل أن حالة تطبيقك موصوفة ككائن عادي. على سبيل المثال ، قد تبدو حالة تطبيق todo كما يلي:

{
  todos: [{
    text: 'Eat food',
    completed: true
  }, {
    text: 'Exercise',
    completed: false
  }],
  visibilityFilter: 'SHOW_COMPLETED'
}

هذا الكائن يشبه "النموذج" باستثناء أنه لا يوجد مستوطنين. هذا بحيث أن أجزاء مختلفة من الكود لا يمكنها تغيير الحالة بشكل تعسفي ، مما يتسبب في خلل يصعب إعادة إنتاجه.

لتغيير شيء ما في الولاية ، تحتاج إلى إرسال إجراء. الإجراء هو كائن جافا سكريبت عادي (لاحظ كيف لا نقدم أي سحر؟) الذي يصف ما حدث. فيما يلي بعض الأمثلة على الإجراءات:

{ type: 'ADD_TODO', text: 'Go to swimming pool' }
{ type: 'TOGGLE_TODO', index: 1 }
{ type: 'SET_VISIBILITY_FILTER', filter: 'SHOW_ALL' }

إن فرض كل تغيير يوصف بأنه إجراء يتيح لنا فهمًا واضحًا لما يحدث في التطبيق. إذا تغير شيء ما ، فنحن نعرف سبب تغيره. الإجراءات تشبه فتات الخبز لما حدث. أخيراً ، لربط الحالة والإجراءات معاً ، نكتب دالة تسمى المخفض. مرة أخرى ، لا شيء سحري حول ذلك - انها مجرد وظيفة تأخذ الدولة والعمل كحجج ، وترجع إلى الحالة التالية من التطبيق. سيكون من الصعب كتابة مثل هذه الوظيفة لتطبيق كبير ، لذلك نكتب وظائف أصغر تدير أجزاء من الولاية:

function visibilityFilter(state = 'SHOW_ALL', action) {
  if (action.type === 'SET_VISIBILITY_FILTER') {
    return action.filter;
  } else {
    return state;
  }
}

function todos(state = [], action) {
  switch (action.type) {
  case 'ADD_TODO':
    return state.concat([{ text: action.text, completed: false }]);
  case 'TOGGLE_TODO':
    return state.map((todo, index) =>
      action.index === index ?
        { text: todo.text, completed: !todo.completed } :
        todo
   )
  default:
    return state;
  }
}

ونكتب مخفضًا آخر يدير الحالة الكاملة لتطبيقنا عن طريق استدعاء هذين المخفّضين لمفاتيح الحالة المقابلة:

function todoApp(state = {}, action) {
  return {
    todos: todos(state.todos, action),
    visibilityFilter: visibilityFilter(state.visibilityFilter, action)
  };
}

هذه هي الفكرة الأساسية لـ Redux. لاحظ أننا لم نستخدم أيًا من واجهات برمجة تطبيقات Redux. يأتي ذلك مع عدد قليل من المرافق لتسهيل هذا النمط ، ولكن الفكرة الأساسية هي أن تصف كيف يتم تحديث حالتك مع مرور الوقت استجابة لأشياء العمل ، و 90 ٪ من الشفرة التي تكتبها هي مجرد جافا سكريبت بسيطة ، بدون استخدام Redux نفسها ، واجهات برمجة التطبيقات الخاصة بها ، أو أي سحر.

لقد قرأت هذه الإجابة ، قللت من نمط معياري ، نظرت إلى أمثلة قليلة من GitHub وحاولت حتى إعادة الصياغة قليلا (تطبيقات todo).

كما أفهم ، توفر الدوافع الرسمية لمستند redux مزايا مقارنة مع معماريات MVC التقليدية. ولكن لا يقدم إجابة على السؤال:

لماذا يجب عليك استخدام Redux عبر Facebook Flux؟

هل هذا فقط مسألة أنماط برمجة: وظيفية مقابل غير وظيفية؟ أو السؤال هو في القدرات / أدوات التطوير التي تلي اتباع نهج إعادة؟ ربما التحجيم؟ أو اختبار؟

هل أنا على حق إذا قلت أن إعادة التكرار هو تدفق للأشخاص الذين ينتمون إلى لغات وظيفية؟

للإجابة عن هذا السؤال ، يمكنك مقارنة مدى تعقيد نقاط التحفيز للتنفيذ في عملية التدفقات العكسية.

في ما يلي نقاط التحفيز من الدوافع الرسمية للمستند :

  1. التعامل مع التحديثات المتفائلة ( كما أفهم ، فإنه لا يكاد يعتمد على النقطة 5. هل من الصعب تنفيذه في fb التمويه؟ )
  2. التقديم على الخادم ( fb flux أيضاً يمكنه القيام بذلك. أي فوائد مقارنة بالإعادة )
  3. إحضار البيانات قبل إجراء التحولات في المسار ( لماذا لا يمكن تحقيقها باستخدام fb flux؟ ما هي الفوائد؟ )
  4. إعادة تحميل ساخنة ( من الممكن مع React Hot Reload . لماذا نحتاج إلى إعادة تشغيل؟ )
  5. تراجع / إعادة الوظائف
  6. أي نقاط أخرى؟ مثل الدولة المستمرة ...

قد يكون من الأفضل لك قراءة هذا المقال من قبل دان أبراموف حيث يناقش العديد من تطبيقات Flux ومفاضلاتها في الوقت الذي كان يكتب فيه Redux: The Evolution of Flux Frameworks

ثانيًا ، لا تبحث صفحة الدوافع التي ترتبط بها حقًا مع دوافع Redux بقدر الدوافع وراء Flux (و React). تعد المبادئ الثلاثة أكثر تحديدًا من Redux بالرغم من أنها لا تعالج فروق التنفيذ من معمارية Flux القياسية.

في الأساس ، يحتوي Flux على العديد من المتاجر التي تقوم بحساب حالة التغيير استجابة لتفاعلات واجهة المستخدم / واجهة برمجة التطبيقات مع المكونات وتبث هذه التغييرات كأحداث يمكن أن تشترك فيها المكونات. في Redux ، يوجد متجر واحد فقط يشترك فيه كل مكون. يبدو أن IMO على الأقل مثل Redux يبسط ويوحد تدفق البيانات من خلال توحيد (أو تقليل ، كما يقول Redux) تدفق البيانات مرة أخرى إلى المكونات - في حين يركز Flux على توحيد الجانب الآخر من تدفق البيانات - عرض ل نموذج.


Redux مؤلف هنا!

لا يكون Redux مختلفًا عن Flux. وعمومًا ، يكون لديه نفس البنية ، ولكن Redux قادر على قطع بعض جوانب التعقيد باستخدام التكوين الوظيفي حيث يستخدم Flux تسجيل الاسترداد.

لا يوجد اختلاف جوهري في Redux ، لكنني أجد أنه يجعل بعض الأفكار التجريدية أسهل ، أو على الأقل من الممكن تنفيذها ، يكون من الصعب أو المستحيل تنفيذها في Flux.

تكوين المخفض

خذ على سبيل المثال ، ترقيم الصفحات. يعالج مثال "Flux + React Router" ترقيم الصفحات ، لكن الرمز لذلك أمر فظيع. أحد أسباب الفظائع هو أن Flux يجعل من غير الطبيعي إعادة استخدام الوظائف عبر المتاجر. إذا كان هناك متجرين في حاجة إلى معالجة الحدود الفاصلة للصفوف استجابةً لإجراءات مختلفة ، فستحتاج إما إلى أن ترث من مخزن أساسي شائع (سيئ! فأنت تقفل نفسك في تصميم معين عند استخدام الميراث) ، أو تستدعي وظيفة من المعالج ، سوف تحتاج إلى العمل بطريقة أو بأخرى على الدولة الخاصة تخزين Flux. كل شيء فوضوي (على الرغم من أنه بالتأكيد في عالم ممكن).

من ناحية أخرى ، فإن ترقيم الصفحات Redux طبيعي بفضل تركيبة المخفض. إنها مخفضات على طول الطريق ، لذا يمكنك كتابة مصنع مخفض يعمل على إنشاء مخفضات ترقيم الصفحات ثم استخدمها في شجرة المخفض . مفتاح السبب في أنه من السهل جدا لأنه في Flux ، تكون المستودعات مسطحة ، ولكن في Redux ، يمكن تداخل المخفضات عن طريق التركيب الوظيفي ، تماما كما يمكن أن تتداخل مكونات React.

يتيح هذا النمط أيضًا ميزات رائعة مثل عدم undo/redo رمز المستخدم undo/redo . هل يمكنك تخيل توصيل Undo / Redo في تطبيق Flux كونه سطرين من الشفرة؟ بالكاد. مع Redux ، يكون ذلك " رائعًا" بفضل نمط تكوين المخفض. أحتاج إلى تسليط الضوء على أنه لا يوجد شيء جديد في هذا الأمر - هذا هو النمط الرائد والموصوف بالتفصيل في Elm Architecture الذي تأثر بنفسه بالتدفق.

تقديم الخادم

لقد قام الناس بالظهور على الخادم على ما يرام مع Flux ، ولكن مع رؤيتنا أن لدينا 20 مكتبة Flux تحاول كل واحدة منها جعل تقديم الخادم "أسهل" ، ربما يكون Flux لديه بعض الحواف الخام على الخادم. والحقيقة هي أن Facebook لا يقدم الكثير من الخوادم ، لذا فهم لم يشعروا بالقلق حيال ذلك ، ويعتمدون على النظام البيئي لتسهيل الأمر.

في المخازن التقليدية ، المخازن هي مفردة. هذا يعني أنه من الصعب فصل البيانات عن الطلبات المختلفة على الخادم. ليس مستحيلا ، ولكن صعب. هذا هو السبب في أن معظم مكتبات Flux (بالإضافة إلى Flux Utils الجديد) تقترح عليك الآن استخدام الفصول بدلاً من المفردات ، حتى تتمكن من إنشاء مخازن لكل طلب.

لا تزال هناك المشاكل التالية التي تحتاج إلى حل في Flux (إما نفسك أو بمساعدة مكتبة Flux المفضلة لديك مثل Flummox أو Alt ):

  • إذا كانت المخازن عبارة عن فصول ، كيف يمكنني إنشاءها وتدميرها مع المرسل لكل طلب؟ متى يمكنني تسجيل المتاجر؟
  • كيف يمكنني ترطيب البيانات من المخازن ثم إعادة ترطيبها على العميل؟ هل أحتاج إلى تنفيذ أساليب خاصة لهذا؟

من المؤكد أن أطر Flux (وليس الفانيلا Flux) لديها حلول لهذه المشاكل ، لكني أجدها أكثر تعقيدا. على سبيل المثال ، يطلب منك Flummox تنفيذ serialize() وإلغاء deserialize() في المتاجر الخاصة بك . Alt يحل هذا ألطف من خلال توفير takeSnapshot() الذي يقوم تلقائياً بتسلسل حالتك في شجرة JSON.

ويذهب Redux إلى أبعد من ذلك: نظرًا لوجود متجر واحد فقط (يتم إدارته بواسطة العديد من أجهزة التخفيض) ، فإنك لا تحتاج إلى أي واجهة برمجة تطبيقات خاصة لإدارة الترطيب (إعادة). لست بحاجة إلى متاجر "التحريك" أو "الهيدرات" ، فهناك متجر واحد فقط ، ويمكنك قراءة حالته الحالية ، أو إنشاء متجر جديد بحالة جديدة. يحصل كل طلب على نسخة متجر منفصلة. اقرأ المزيد حول تقديم الخادم باستخدام Redux.

مرة أخرى ، هذه حالة لشيء محتمل في كل من Flux و Redux ، لكن مكتبات Flux تحل هذه المشكلة عن طريق إدخال نصف طن من API والاتفاقيات ، ولا يلزم حتى أن يقوم Redux بحلها لأنه ليس لديها هذه المشكلة في المكان الأول بفضل البساطة المفاهيمية.

تجربة المطور

لم أكن في الواقع أعتزم أن تصبح Redux مكتبة Flux شعبية - كتبت ذلك عندما كنت أعمل في حديث ReactEurope على إعادة التحميل الساخن مع السفر عبر الزمن . كان لدي هدف رئيسي واحد: جعل من الممكن تغيير كود المخفض على الطاير أو حتى "تغيير الماضي" عن طريق تجاوز الإجراءات ، والاطلاع على الحالة التي يتم إعادة حسابها.

لم أر مكتبة Flux واحدة قادرة على القيام بذلك. React Hot Loader لا يتيح لك القيام بذلك - في الواقع ينكسر إذا قمت بتحرير مخازن Flux لأنه لا يعرف ما يجب فعله بها.

عندما يحتاج Redux إلى إعادة تحميل رمز المخفض ، فإنه يستدعي replaceReducer() ، ويعمل التطبيق مع الرمز الجديد. في Flux ، تشابك البيانات والوظائف في متاجر Flux ، لذلك لا يمكنك "استبدال الوظائف فقط". علاوة على ذلك ، سيكون عليك إعادة تسجيل الإصدارات الجديدة بطريقة أو بأخرى مع برنامج الإرسال - وهو أمر لا يمتلكه Redux حتى.

النظام البيئي

يمتلك Redux نظامًا إيكولوجيًا غنيًا وسريع النمو . هذا لأنه يوفر بعض نقاط الامتداد مثل middleware . وقد تم تصميمه مع حالات الاستخدام مثل logging ، وتقديم الدعم Promises ، Observables ، routing ، وفحوصات التحقق من عدم persistence ، persistence ، وما إلى ذلك ، في الاعتبار. لن يكون كل هذا مفيدًا ، ولكن من الجيد الوصول إلى مجموعة من الأدوات التي يمكن دمجها بسهولة للعمل معًا.

بساطة

يحافظ Redux على جميع مزايا Flux (تسجيل وإعادة تشغيل الإجراءات وتدفق البيانات أحادي الاتجاه والطفرات التابعة) ويضيف فوائد جديدة (إعادة التراجع السهل وإعادة التحميل السريع) دون إدخال مرسل وتسجيل المتجر.

من المهم إبقائها بسيطة لأنها تبقيك عاقلًا بينما تقوم بتطبيق تجريدات مستوى أعلى.

على عكس معظم مكتبات Flux ، يكون سطح واجهة برمجة تطبيقات Redux صغيرًا. إذا أزلت تحذيرات مطوِّري البرامج والتعليقات وعمليات التحقق من السلامة ، فستكون 99 سطرًا . لا يوجد رمز async صعبة لتصحيح.

يمكنك في الواقع قراءتها وفهم كل من Redux.

انظر أيضا جوابي على الجوانب السلبية لاستخدام Redux مقارنة بالتدفق .


عملت لفترة طويلة مع Flux والآن لفترة طويلة باستخدام Redux. كما أشار دان إلى أن كلا المعماريين ليسا مختلفين. الشيء هو أن Redux يجعل الأشياء أبسط وأنظف. يعلمك بضعة أشياء على قمة الجريان. مثل على سبيل المثال Flux هو مثال مثالي لتدفق البيانات ذات الاتجاه الواحد. الفصل بين المخاوف عندما يكون لدينا بيانات ، يتم الفصل بين التلاعب بها وطبقة العرض. في Redux لدينا نفس الأشياء ولكننا نتعلم أيضا عن ثبات وظائف نقية.


هنا هو التفسير البسيط لـ Redux over Flux. ليس لدى Redux جهاز إرسال. يعتمد على وظائف نقية تسمى مخفضات. لا يحتاج المرسل. يتم التعامل مع كل إجراءات بواسطة مخفض واحد أو أكثر لتحديث المتجر الواحد. بما أن البيانات غير قابلة للتغيير ، فإن المخفضات تقوم بإرجاع حالة محدثة جديدة تقوم بتحديث المتجر

لمزيد من المعلومات http://www.prathapkudupublog.com/2017/04/flux-vs-redux.html


أفضّل استخدام Redux نظرًا لأنه يستخدم متجرًا واحدًا مما يجعل إدارة الولاية أكثر سهولة مقارنة بـ Flux ، كما أن Redux DevTools هي أدوات مفيدة حقًا تتيح لك معرفة ما تفعله بحالتك من خلال بعض البيانات المفيدة وهي تتوافق حقًا مع React تطوير الأدوات.

كما حصلت Redux على مرونة أكبر في استخدام الأطر الشائعة الأخرى مثل Angular . على أي حال ، دعونا نرى كيف يقدم Redux نفسه كإطار عمل.

يحتوي Redux على ثلاثة مبادئ يمكنها تقديم Redux جيدًا ، كما أنها تمثل الفرق الرئيسي بين Redux و Flux أيضًا.

مصدر واحد للحقيقة

يتم تخزين حالة التطبيق الخاص بك بالكامل في شجرة كائن داخل متجر واحد.

وهذا يجعل من السهل إنشاء تطبيقات عالمية ، حيث يمكن إجراء تسلسل للدولة من خادمك وترقيتها إلى العميل دون جهد إضافي لترميز. تسهل أيضاً شجرة حالة واحدة التصحيح أو التحقق من أحد التطبيقات ؛ كما يمكّنك من مواصلة حالة تطبيقك في التطوير ، من أجل دورة تطوير أسرع. بعض الوظائف التي كان من الصعب تنفيذها تقليديًا - التراجع / الإعادة ، على سبيل المثال - يمكن أن تصبح فجائية تافهة ، إذا تم تخزين كل حالتك في شجرة واحدة.

console.log(store.getState())

/* Prints
{
  visibilityFilter: 'SHOW_ALL',
  todos: [
    {
      text: 'Consider using Redux',
      completed: true,
    },
    {
      text: 'Keep all state in a single tree',
      completed: false
    }
  ]
}
*/

الولاية للقراءة فقط

الطريقة الوحيدة لتغيير الحالة هي إصدار عمل ، كائن يصف ما حدث.

يضمن ذلك عدم كتابة طرق العرض ولا عمليات رد الاتصال على الشبكة إلى الحالة مطلقًا. بدلا من ذلك ، يعبرون عن نية لتغيير الدولة. نظرًا لأن جميع التغييرات تتم مركزيًا وتحدث واحدة تلو الأخرى وفقًا لترتيب صارم ، فلا توجد شروط سباق دقيقة يجب الانتباه لها. نظرًا لأن الإجراءات هي مجرد كائنات بسيطة ، فيمكن تسجيلها وتسلسلها وتخزينها ثم إعادة تشغيلها لاحقًا لأغراض التصحيح أو الاختبار.

store.dispatch({
  type: 'COMPLETE_TODO',
  index: 1
})

store.dispatch({
  type: 'SET_VISIBILITY_FILTER',
  filter: 'SHOW_COMPLETED'
})

يتم إجراء التغييرات مع وظائف نقية

لتحديد كيفية تحويل شجرة الحالة بواسطة إجراءات ، تكتب مخفّفات نقية.

المخفضات هي مجرد وظائف نقية تأخذ الحالة السابقة والإجراء ، وتعيد الحالة التالية. تذكر إعادة كائنات الحالة الجديدة ، بدلاً من تحور الحالة السابقة. يمكنك البدء باستخدام مخفض واحد ، ومع نمو تطبيقك ، يمكنك تقسيمه إلى مخفضات أصغر تقوم بإدارة أجزاء معينة من شجرة الحالة. نظرًا لأن المخفضات هي مجرد وظائف ، يمكنك التحكم في الترتيب الذي يتم الاتصال به ، أو تمرير بيانات إضافية ، أو حتى إنشاء مخفضات قابلة لإعادة الاستخدام للمهام الشائعة مثل ترقيم الصفحات.

function visibilityFilter(state = 'SHOW_ALL', action) {
  switch (action.type) {
    case 'SET_VISIBILITY_FILTER':
      return action.filter
    default:
      return state
  }
}

function todos(state = [], action) {
  switch (action.type) {
    case 'ADD_TODO':
      return [
        ...state,
        {
          text: action.text,
          completed: false
        }
      ]
    case 'COMPLETE_TODO':
      return state.map((todo, index) => {
        if (index === action.index) {
          return Object.assign({}, todo, {
            completed: true
          })
        }
        return todo
      })
    default:
      return state
  }
}

import { combineReducers, createStore } from 'redux'
let reducer = combineReducers({ visibilityFilter, todos })
let store = createStore(reducer)

لمزيد من المعلومات ، تفضل بزيارة here





javascript reactjs reactjs-flux flux redux