Redux: ما هي عيوب تخزين كل حالتك في ذرة واحدة غير قابلة للتغيير؟

تم إنشاؤها على ١٠ فبراير ٢٠١٦  ·  91تعليقات  ·  مصدر: reduxjs/redux

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

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

أشعر بالفضول فقط لأنه لا ينطبق فقط على الإعادة ، ولكن في بعض القدرات على أشياء أخرى مثل Om ، datomic والتي تتحدث عن قلب قاعدة البيانات من الداخل إلى الخارج . أنا أحب redux ، أحب Om ، أنا مهتم بالبيانات ، وقد أحببت هذا الحديث حقًا.

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

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

لأنكم ربما فكرتم في هذا الأمر أكثر مما فكرت به ، هل يمكنكم المساعدة في توضيح ذلك بالنسبة لي؟

discussion docs question

التعليق الأكثر فائدة

Redux هو في الأساس مصادر الأحداث حيث يوجد إسقاط واحد للاستهلاك.

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

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

إن تقديم هذه الحالة من القمة ، حسب تجربتي ، ليس ملائمًا كما أنه لا يؤدي دائمًا بشكل كافٍ (على الأقل مع React الذي ربما لا يكون أسرع تطبيق لـ VDom). يحل Redux هذا الأمر بـ connect ولكن مع زيادة عدد الاتصال ، يمكن أن يصبح عنق الزجاجة. هناك حلول

كما أن هياكل البيانات الثابتة مثل ImmutableJS لا تقدم دائمًا أفضل أداء في بعض العمليات ، مثل إضافة عنصر في فهرس عشوائي في قائمة كبيرة (انظر تجربتي في عرض القوائم الكبيرة هنا )

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


أتفق أيضًا مع jquense

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

يتطلب تركيب أي حالة في متجر Redux المزيد من النماذج المعيارية. ربما تحل هندسة Elm هذا بطريقة أكثر أناقة ولكنها تتطلب أيضًا الكثير من النماذج.

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

  • مدخلات النص
  • موقف التمرير
  • حجم منفذ العرض
  • موقف الماوس
  • موقف الإقحام / الاختيار
  • بيانات قماشية
  • حالة غير قابلة للتسلسل
  • ...

ال 91 كومينتر

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

شكرا جزيلا! كنت حقا أريد أن أسمع عن هذا.

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

هذا النوع من الأسئلة الصعبة مثل مشاريع ب / ج مثل OM و redux وغيرها من libs ذات الحالة المفردة ، تخفف بفعالية الجوانب السلبية. بدون قيود الثبات ، والوصول المحكوم ببوابة ، لا تختلف ذرة الحالة الواحدة على الإطلاق عن إرفاق جميع بياناتك بـ window (والتي تُعرف جوانبها السلبية)

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

لم يكن أي من هذه الجوانب السلبية محظورًا بشكل خاص بالنسبة لنا على الرغم من :)

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

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

الشيء الذي ناضلت معه ، كمستخدم جديد هو أكثر شيء يحاول التغلب على كل من تغيير أسلوب الترميز (imho) المتطرف في Redux ، والتغييرات المفاهيمية في نفس الوقت ؛ لا يزال الأمر شاقًا بعض الشيء حتى الآن ، بعد شهر وتغيير بعد محاولة الغوص فيه ؛ إنني أتطلع إلى https://github.com/ngrx/store التالي للتعرف على المفاهيم ولكن بنمط / بناء أكثر مألوفًا والمزيد من بقية الإطار الضمني / المقدم.

أفهم أنه بالنسبة للبعض ، الإطار هو عكاز ؛ لكن البعض منا بحاجة إلى هؤلاء ؛ قلة من الناس سيكونون في صدارة لعبتهم بما يكفي للحصول على آراء قوية مفيدة ، لذا فإن الأطر أفضل من التخبط في الظلام ، كما تعلم؟ هذه نقطة مني ، أنا مبرمج متوسط ​​العمر جديد على المفاهيم :)

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

ليس خطأك ، ولكن لا تزال مشكلة أرغب في حلها :)

أعتقد أن السؤال الأكبر الذي لا يزال لدي في هذه المرحلة هو ، أين يجب أن تذهب أي عناصر غير قابلة للتسلسل مثل الوظائف أو الأمثلة أو الوعود؟ كنت أتساءل عن هذا الأمر في Reactiflux الليلة الماضية ولم تحصل على أي ردود جيدة. كما شاهدت للتو شخصًا ما ينشر http://stackoverflow.com/questions/35325195/should-i-store-function-references-in-redux-store .

حالة الاستخدام لمتاجر متعددة (ضع في اعتبارك أن هذا هو أفضل ما يمكن أن أفكر فيه):

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

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

gaearon نحن نبني منصة تداول. لقد شرحت لك سابقًا مرة لماذا لا يصلح متجر واحد لنا (بعد لقاء React.js في سانت بطرسبرغ). سأحاول شرحها مرة أخرى بالتفصيل (في منشور مدونة على المستوى المتوسط؟) ولكن ربما أحتاج إلى مساعدة بسبب مهاراتي في اللغة الإنجليزية :) هل من الجيد أن أرسلها إليك أو إلى شخص آخر هنا لمراجعتها في Twitter مباشرة رسائل متى سيتم ذلك؟ لا يمكنني تسمية التاريخ المحدد على الرغم من أنني سأحاول كتابة هذا المنشور قريبًا (على الأرجح نهاية هذا الشهر).

ونعم ، ما زلنا نستخدم Redux مع متاجر متعددة من خلال انتهاك بعض القواعد من المستندات كما قال timdorr (بتكلفة ذلك لا يمكننا استخدام react-redux بشكل مريح في الحالات التي نحتاج فيها إلى بيانات من متاجر مختلفة كما هي في حالة وجود متجر واحد)

Redux هو في الأساس مصادر الأحداث حيث يوجد إسقاط واحد للاستهلاك.

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

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

إن تقديم هذه الحالة من القمة ، حسب تجربتي ، ليس ملائمًا كما أنه لا يؤدي دائمًا بشكل كافٍ (على الأقل مع React الذي ربما لا يكون أسرع تطبيق لـ VDom). يحل Redux هذا الأمر بـ connect ولكن مع زيادة عدد الاتصال ، يمكن أن يصبح عنق الزجاجة. هناك حلول

كما أن هياكل البيانات الثابتة مثل ImmutableJS لا تقدم دائمًا أفضل أداء في بعض العمليات ، مثل إضافة عنصر في فهرس عشوائي في قائمة كبيرة (انظر تجربتي في عرض القوائم الكبيرة هنا )

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


أتفق أيضًا مع jquense

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

يتطلب تركيب أي حالة في متجر Redux المزيد من النماذج المعيارية. ربما تحل هندسة Elm هذا بطريقة أكثر أناقة ولكنها تتطلب أيضًا الكثير من النماذج.

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

  • مدخلات النص
  • موقف التمرير
  • حجم منفذ العرض
  • موقف الماوس
  • موقف الإقحام / الاختيار
  • بيانات قماشية
  • حالة غير قابلة للتسلسل
  • ...

هذا السؤال الذي رأيته للتو على SO:

http://stackoverflow.com/questions/35328056/react-redux-should-all-component-states-be-kept-in-redux-store

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

بالإضافة إلى ذلك ، قد يكون هذا عائقًا إذا كنت تحاول تنفيذ شيء مثل هذا https://github.com/ericelliott/react-pure-component-starter حيث يكون كل مكون نقيًا وليس له رأي في حالته الخاصة .

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

زيادة احتمال اصطدام مفاتيح الحالة بين المخفضات.
تعد طفرات البيانات والإعلانات بعيدة عن الكود حيث يتم استخدام البيانات (عندما نكتب رمزًا نحاول وضع إعلانات المتغيرات بالقرب من المكان الذي نستخدمها فيه)

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

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

بعض الأسباب التي تجعل حالة الرسوم المتحركة محرجة بالنسبة إلى Redux:

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

من ناحية أخرى ، هناك بالتأكيد تحديات أمام بناء حالة الرسوم المتحركة بالكامل خارج شجرة حالة Redux.

إذا حاولت عمل الرسوم المتحركة بنفسك عن طريق معالجة DOM ، فيجب عليك الانتباه لأشياء مثل هذه:

  • لن يأخذ virtual-dom diffs في الحسبان التلاعب بالرسوم المتحركة ، مثل الأنماط المخصصة التي تحددها على العقدة - إذا قمت بتعيين بعض الأنماط على عقدة DOM ، فيجب عليك إزالتها بنفسك إذا كنت تريدها أن تختفي
  • إذا قمت بإجراء رسوم متحركة على المستند نفسه ، فيجب أن تكون مدركًا بشكل مؤلم لتحديثات النطاق الظاهري - يمكنك بدء رسم متحرك على عقدة DOM واحدة ، فقط لتجد أن محتوى عقدة DOM هذه قد تغير أثناء الحركة
  • إذا كنت تؤدي رسومًا متحركة على المستند نفسه ، فيجب أن تكون حذرًا من أنماط وسمات الكتابة الافتراضية لـ dom والتي تعيّنها على عقدتك ، وعليك أن تكون حذرًا من الكتابة فوق الأنماط والسمات التي حددتها Virtual-dom

وإذا حاولت السماح لـ Virtual-dom بالاهتمام بكل عمليات التلاعب في DOM (وهو ما يجب عليك!) ولكن دون الاحتفاظ بحالة الرسوم المتحركة في Redux ، فسوف ينتهي بك الأمر مع هذه المشكلات الصعبة مثل هذه:

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

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

بالنسبة لأي شخص فضولي ، فإن أفضل حل وجدته لـ Redux + virtual-dom هو الاحتفاظ بذرتين من الحالة: Redux يحافظ على حالة التطبيق الأساسية ، ويحافظ على المنطق الأساسي لمعالجة هذه الحالة استجابةً للإجراءات ، وما إلى ذلك. الحالة الأخرى هو كائن قابل للتغيير ويحمل حالة الرسوم المتحركة (أستخدم mobservable). الحيلة إذن هي الاشتراك في كل من تغييرات حالة Redux _ و_ تغييرات حالة الرسوم المتحركة ، وتقديم واجهة المستخدم كدالة لكليهما:

/* Patch h for jsx/vdom to convert <App /> to App() */
import h from './h'
import { diff, patch, create } from 'virtual-dom'
import { createStore } from 'redux'
import { observable, autorun } from 'mobservable'
import TWEEN from 'tween.js'
import rootReducer from './reducers'
import { addCard } from './actions'
import App from './containers/App'

// Redux state
const store = createStore()

// Create vdom tree
let tree = render(store.getState())
let rootNode = create(tree)
document.body.appendChild(rootNode)

// Animation observable
let animationState = observable({
  opacity: 0
})

// Update document when Redux state 
store.subscribe(function () {
  // ... anything you need to do in response to Redux state changes
  update()
})

// Update document when animation state changes
autorun(update)

// Perform document update with current state
function update () {
  const state = store.getState()
  let newTree = render(state, animationState)
  let patches = diff(tree, newTree)
  rootNode = patch(rootNode, patches)
  tree = newTree
}

// UI is a function of current state (and animation!)
function render (state, animation = {}) {
  return (
    <App {...state} animation={animationState} />
  )
}

// Do some animations
function animationLoop (time) {
  window.requestAnimationFrame(animationLoop)
  TWEEN.update(time)
}
animationLoop()

new TWEEN.Tween(animationState)
      .to({ opacity: 100 }, 300)
      .start()

// Or when you dispatch an action, also kick off some animation changes...
store.dispatch(addCard())
/* etc... */

شكرا لكم جميعا على الردود الرائعة! دعهم يأتون.

شيء واحد يجب ملاحظته هو أننا لا ننوي استخدام Redux في _ all_ state. فقط كل ما يبدو مهمًا للتطبيق. أود أن أزعم أنه يجب معالجة المدخلات وحالة الرسوم المتحركة بواسطة React (أو أي تجريد آخر للحالة المؤقتة). يعمل Redux بشكل أفضل مع أشياء مثل البيانات التي تم جلبها والنماذج المعدلة محليًا.

تضمين التغريدة

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

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

تضمين التغريدة

زيادة احتمال اصطدام مفاتيح الحالة بين المخفضات.

هل تمانع في شرح كيفية حدوث ذلك بمزيد من التفصيل؟ عادة نقترح عليك تشغيل مخفض واحد فقط على أي شريحة حالة. كيف يمكن أن تحدث الاصطدامات؟ هل تقوم بتمريرات متعددة على الدولة؟ إذا كان الأمر كذلك لماذا؟

gaearonistarkov: ربما ما يعني أن العديد من الإضافات والمكتبات ذات الصلة قد تتسابق لنفس مساحة على مستوى أعلى؟ تريد المكتبة A مفتاحًا علويًا يسمى "myState" ، وكذلك تفعل Library B ، وما إلى ذلك.

نعم ، هذه نقطة جيدة حتى لو لم يكن هذا ما يعنيه istarkov . (لا أعرف.) بشكل عام ، يجب أن تقدم المكتبات طريقة لتركيب جهاز تخفيض السرعة في أي مكان في الشجرة ولكني أعلم أن بعض المكتبات لا تسمح بذلك.

تضمين التغريدة

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

سأكون سعيدا ب! سأفعل ذلك عندما أحصل على لحظة.

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

سأكون سعيدًا للدردشة حول هذا الموضوع بعيدًا عن الموضوع ، فقد أكون مخطئًا جدًا.

taggartbg : تحدث تمامًا دون معرفة شكل الكود الخاص بك هنا. هل تتحدث عن محاولة التعامل مع دولة تبدو هكذا؟

{ groupedData : { first : {a : 1, b : 2}, second : {a : 3, b : 4}, third : {a : 5, b, 6} }

يبدو أنه يمكنك التعامل مع ذلك على جانب المخفض من خلال وجود وظيفة مخفض واحدة تأخذ مفتاح معرف كل مجموعة كجزء من كل إجراء. في الواقع ، هل نظرت إلى شيء مثل https://github.com/erikras/multireducer أو https://github.com/lapanoid/redux-delegator أو https://github.com/reducks/redux-multiplex أو https://github.com/dexbol/redux-register؟

أيضًا ، على جانب إعادة التحديد ، قد تساعد حقيقة أن React-Redux يدعم الآن المحددات لكل مكون ، لأن ذلك يحسن السيناريوهات التي تقوم فيها بالتحديد بناءً على عناصر المكون.

تضمين التغريدة

شيء واحد يجب ملاحظته هو أننا لا ننوي استخدام Redux لجميع الحالات. فقط كل ما يبدو مهمًا للتطبيق. أود أن أزعم أنه يجب معالجة المدخلات وحالة الرسوم المتحركة بواسطة React (أو أي تجريد آخر للحالة المؤقتة). يعمل Redux بشكل أفضل مع أشياء مثل البيانات التي تم جلبها والنماذج المعدلة محليًا.

مطور React الذي يقرأ المستندات والبرنامج التعليمي لديه بالفعل تجريد الحالة المؤقتة هذا تحت تصرفه ، لذلك من الممكن أن يكون هذا بالفعل في الاعتبار عند التفكير في المكان الذي يكون فيه Redux منطقيًا لمشروع ما.

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

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

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

gaearon أجرينا محادثة شيقة على Cycle.js حول الاختلافات المعمارية بين حالة ذرة واحدة مقابل بيبينج. هنا .

أعلم أن هذا ليس مرتبطًا بـ Redux بنسبة 100٪ ولكني أردت إعطاء منظور مختلف عن تطبيق يستخدم تدفقات يمكن ملاحظتها كتدفق بيانات حول أحد التطبيقات (لكون التطبيق عبارة عن مجموعة من الوظائف البحتة).

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

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

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

يمكن أيضًا للقادمين الجدد إلى التطبيق (إذا فهموا Cycle of course) توصيل النقاط بسهولة ورسم تمثيل مرئي سريع في ذهنهم لكيفية معالجة الحالة وتوصيلها وكل هذا من الكود.

آسف مقدمًا إذا كان هذا خارج السياق تمامًا ، وأردت إظهار كيف أجرى نموذج مختلف محادثة مماثلة: مبتسم:

تضمين التغريدة

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

أعتقد أنه من الأفضل أن يكون لعنصر واجهة المستخدم حالته الخاصة (ربما حتى يكون متجرًا خاصًا به (إعادة؟)) حتى يمكنه العمل بشكل مستقل في أي تطبيق (mashup-) ولا يتلقى سوى بعض الخصائص. فكر في أداة الطقس. يمكنه جلب البيانات وإظهارها بنفسه واستلام خصائص مثل المدينة والطول والعرض فقط. مثال آخر هو أداة Twitter.

chicoxyzzy ذات الصلة: https://github.com/rackt/react-redux/issues/278

مناقشة رائعة!

بشكل أساسي ، أجد أنه من غير الملائم الجمع بين تطبيقات / مكونات / مكونات إضافية متعددة.

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

فمثلا:

أنا أقوم بإنشاء برنامج مراسلة يشبه iMessage. حالة إعادة التشغيل هي currentConversationId إلخ. يحتوي مكوّن Messenger على @connect(state => ({ currentConversationId: state.messenger.currentConversationId })) .

أريد تضمين Messenger في تطبيق جديد. سأحتاج إلى import { rootReducer as messengerRootReducer } from 'my-messenger' وإضافته إلى combineReducers({ messenger: messengerRootReducer }) حتى يعمل.

الآن ، إذا كنت أرغب في الحصول على مثيلين <Messenger> في التطبيق بهما بيانات مختلفة ، فلا يمكنني ذلك ، لأنني مرتبط بـ state.messenger في مكون Messenger. صناعةالعمل مقابل شريحة معينة من المتجر سيجعلني أستخدم @connect المخصص.

أيضًا ، لنفترض أن التطبيق المحتوي يحتوي على اسم إجراء معين موجود في الوحدة النمطية my-messenger ، سيكون هناك تصادم. هذا هو السبب في أن معظم ملحقات redux لها بادئات مثل @@router/UPDATE_LOCATION .

بعض الأفكار العشوائية / المجنونة:

1

@connect الاتصال بشريحة معينة من المتجر ، لذلك يمكنني تضمين تطبيقي عدة <Messenger> s تتصل بشريحة البيانات الخاصة بهم ، مثل state.messenger[0] / state.messenger[1] . يجب أن يكون شفافًا إلى <Messenger> والذي لا يزال متصلاً بـ state.messenger ، ومع ذلك ، يمكن أن يوفر التطبيق المحتوي الشريحة بشيء مثل:

@connect(state => ({ messengers: state.messengers }))
class App extends Component {
  render() {
    return (
      <div>
        {this.props.messengers.map(messenger =>
          <ProvideSlice slice={{messenger: messenger}}><Messenger /></ProvideSlice>
        }
      </div>
    )
  }
}

هناك مشكلة عند استخدام الكيانات الموحدة العالمية ، يجب أيضًا أن يكون state.entities موجودًا ، لذلك إلى جانب الحالة المقطوعة ، يجب أن تكون الحالة بأكملها موجودة بطريقة ما. ProvideSlice تعيين بعض السياق الذي يمكن لـ Messenger 's @connect القراءة منه.

هناك مشكلة أخرى وهي كيفية ربط الإجراءات التي تم إطلاقها بواسطة المكونات في <Messenger> تؤثر فقط على تلك الشريحة. ربما يكون لديك @connect أقل من ProvideSlice تشغيل mapDispatchToProps الإجراءات فقط على تلك الشريحة من الولاية.

2

اجمع بين تعريفات store و reducer ، لذلك يمكن أيضًا أن يكون كل مخفض مستقلًا. يبدو التخزين وكأنه وحدة تحكم بينما المخفض هو عرض. إذا اتخذنا نهج رد الفعل ، "كل شيء مكون" (على عكس توجيه / تحكم الزاوية 1.x) ، فقد يسمح للمكونات وحالتها / أفعالها أن تكون مستقلة حقًا. بالنسبة لأشياء مثل الكيانات العادية (أي "الحالة العالمية") ، يمكن استخدام شيء مثل سياق React ، ويمكن الوصول إليه من خلال جميع الإجراءات (على سبيل المثال getState في thunk ) / المكونات المتصلة.

elado ومعظم فكرة ذكية رأيت الآن هو مهندس مع "مقدمي" في الاعتبار: https://medium.com/@timbur/react أوتوماتيكية-مسترجع مقدمي-ونسخ متماثلة-c4e35a39f1

تضمين التغريدة أنا في رحلة على الطريق قليلاً ولكن عندما تسنح لي الفرصة ، أخطط لكتابة مقال آخر يصف مقدمي الخدمة بشكل أكثر إيجازًا لمن هم على دراية بالفعل بـ React و Redux. يجب على أي شخص مألوف بالفعل أن يجد الأمر بسيطًا / سهلًا. :)

_تم نقل التعليق إلى https://github.com/loggur/react-redux-provide/issues/8_

gaearon ما زلت ترغب في سماع أفكارك حول هذا.

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

gaearon أي أفكار حول كيفية البدء في تنفيذ مثل هذا النظام؟

تضمين التغريدة

بعبارة أخرى ، أود أن أرى شيئًا مثل نموذج الحالة المحلية React لكن مدعومًا بمخفضات

أعتقد أن الجزء الصعب هو أن حالة React المحلية مرتبطة بدورة حياة أحد المكونات ، لذلك إذا حاولت نمذجة الحالة المحلية في Redux ، فسيكون لديك حساب لـ "mounting" و "unmounting". لا توجد لدى Elm هذه المشكلة لأن 1) المكونات ليس لها دورات حياة ، و 2) "تركيب" عرض ما مشتق من النموذج ، بينما في React ، الحالة المحلية موجودة فقط _ بعد_ تم تثبيت عرض. (تحرير: أكثر دقة للقول مباشرة قبل تركيبها ، ولكن بعد اتخاذ قرار التثبيت بالفعل)

ولكن كما تلمح إلى ، فإن Elm Architecture - التي تسير "على طول الطريق" لأعلى - لها عيوبها الخاصة ولا تتناسب مع كل ذلك جيدًا مع دورة التحديث والمصالحة في React (على سبيل المثال ، تتطلب استخدامًا متحرراً لتحسينات shouldComponentUpdate() ... الذي ينكسر إذا "أعدت" بسذاجة طريقة إرسال داخل render() .)

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

أعتقد أن هذا ما يحاول threepointone حله باستخدام https://github.com/threepointone/redux-react-local

acdlite ، النموذج المفاهيمي لـ Elm يعمل بشكل رائع للدولة المحلية ، لكنه يبدو حقًا وكأنه ألم لاستخدامه في تطبيقات العالم الحقيقي حيث يتعين علينا استخدام المكتبات ، والتركيز على التركيب ، والتعامل مع تأثيرات المنظر أو أي شيء آخر ... راجع https: // github.com/evancz/elm-architecture-tutorial/issues/49

slorber نعم أوافق. أليس هذا ما قلته للتو؟ :د

أفترض أن مخاوفك مختلفة قليلاً. _If_ (كبيرة "if") كنت ستستخدم Elm Architecture في React ، على الرغم من ذلك ، لا أعتقد أنك ستواجه المشكلات التي ذكرتها لأنه لا يزال لدينا إمكانية الوصول إلى دورات الحياة ، و setState باعتبارها فتحة هروب ، وما إلى ذلك.

نعم نحن في نفس الصفحة acdlite
تحل بنية Elm مع React هذه المشكلة.
حتى Elm قد في المستقبل لأنه قد يسمح باستخدام خطافات vdom.

ومع ذلك ، تتطلب بنية Elm بعض النماذج المعيارية. أعتقد أنه ليس مستدامًا حقًا ما لم تستخدم Flow أو Typescript لتغليف / فك الإجراءات ، وسيكون من الأفضل أن يكون لديك طريقة أكثر بساطة للتعامل مع هذه الحالة المحلية ، مثل حل threepointone

لدي اهتمام آخر بهندسة Elm وهو أن الإجراء المتداخل يعمل بشكل رائع لحالة المكون المحلي ، لكنني أعتقد أنها ليست فكرة جيدة بمجرد أن تحتاج إلى الاتصال بين المكونات المنفصلة. إذا كان يجب على widget1 إلغاء تغليف الإجراءات المتداخلة بعمق واستبطانها للعثور على حدث تم إطلاقه بواسطة عنصر واجهة المستخدم 2 ، فهناك مشكلة في الاقتران. لقد عبرت عن بعض الأفكار هنا وأعتقد أن استخدام Elm مع "علب بريد" يمكن أن يؤدي المهمة. هذا أيضًا ما يمكن أن تساعده ملحمة redux في البنيات غير الدائرية ذات الأحداث المسطحة.

بدأت في الحصول على فكرة جيدة حول كيفية تصميم تطبيقات redux قابلة للتطوير وسأحاول كتابة شيء عنها عندما أكون أقل انشغالًا

gaearon هل تتحدث عن react-redux-provide في آخر مشاركة لك هنا؟ أنا أسأل لأنه إذا كنت كذلك ، بناءً على ردك ، فمن الواضح أنك لم تلقي نظرة فاحصة كافية عليه.

أيضًا ، فيما يتعلق بذكرacdlite لإضفاء الطابع الخارجي على شجرة الحالة ، فهذه هي المشكلة التي صمم مقدمو الخدمات لحلها.

واجهة برمجة التطبيقات التي يوفرها مصمم الديكور provide هي بالتأكيد فكرة مجردة ونعم ، فهي تعتمد حاليًا على redux ، لكن التفكير فيها على أنها تعتمد على redux هي طريقة خاطئة فكر في الأمر ، نظرًا لأنه في الحقيقة مجرد بعض "الغراء" بين المكونات وشجرة الحالة ، حيث أن React context لم يتم تطويره بالكامل بعد. فكر في الأمر كطريقة مثالية لمعالجة وتمثيل شجرة (شجرات) الحالة عبر actions و reducers (أي حالة المتجر) كـ props ، حيث يمكنك للإعلان بشكل أساسي عن actions و reducers كـ propTypes (و / أو contextTypes في المستقبل) بشكل مشابه لكيفية import أي شيء آخر داخل تطبيقك. عندما تفعل هذا ، يصبح كل شيء سهل التفكير فيه بجنون. من المحتمل أن تتطور تكلفة React context لتشمل هذه الميزات الأساسية ، وفي هذه الحالة ، قد يستغرق الأمر ثانيتين كاملتين لإزالة grep وإزالة @provide و import provide from 'react-redux-provide' لذلك ثم تركت بمكونات بسيطة لم تعد تعتمد عليها. وإذا لم يحدث ذلك أبدًا ، فلن يكون هناك مشكلة كبيرة لأن كل شيء سيستمر في العمل بشكل مثالي ومتوقع.

أعتقد أنك تبالغ في تبسيط المشكلة. ما زلت بحاجة إلى حل مشكلة التركيب والفك.

acdlite هل حصلت على مثال؟

إذا كان أحد الأشياء التي تشير إليها (على سبيل المثال) هو استرداد props من بعض قواعد البيانات بناءً على بعض id أو أيًا كان ، هذا (من بين أي تطبيق عملي آخر تقريبًا يمكنك التفكير فيه) يمكن تحقيقه بسهولة مع مقدمي الخدمة. بعد أن أنهيت بعض الأشياء الأخرى التي أعمل عليها ، يسعدني أن أوضح لكم مدى سهولة ذلك. :)

قد يكون مثيرًا للاهتمام: مقارنة عمليات تنفيذ الحالة التفاعلية .
Elm و Redux و CycleJS ... (العمل قيد التقدم)

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

نحن في مرحلة التصميم / التطوير المبكر لتطبيق 1.x الزاوي مع مجموعة عقلية التطوير الزاوي 2.0 والتفكير في استخدام الإعادة. في الماضي ، كنا نستخدم التدفق مع متاجر متعددة تستجيب لبعض الإرساليات الشائعة وبعض الإرساليات المخصصة.

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

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

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

VivekPMenon : ما هي مخاوفك المحددة؟ حجم شجرة الدولة؟ القدرة على إجراءات مساحة الاسم / إبقاء المخفضات معزولة؟ القدرة على إضافة أو إزالة المخفضات بشكل ديناميكي؟

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

تضمين التغريدة شكرا جزيلا على الرد. حيرتي هي في الغالب حول النقطة الثانية (العزلة). افترض أن أحد فرقنا يقوم بإنشاء عنصر واجهة مستخدم A يعتمد على التدفق ويحتاج إلى استخدام المتجر لإدارة حالته. افترض أنهم سينشئون حزمة jspm / npm إذا قاموا بتوزيعها. هذا هو الحال مع فريق آخر يقوم بإنشاء عنصر واجهة المستخدم B. هذه عناصر واجهة مستخدم / حزم مستقلة ولا تحتاج إلى تبعية مباشرة / غير مباشرة لبعضها البعض.

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

VivekPMenon هذا سؤال صالح يحاول البعض منا حله.

يمكنك الحصول على بعض الأفكار هنا: https://github.com/slorber/scalable-frontend-with-elm-or-redux

ألقِ نظرة أيضًا على إجابتي حول Redux-saga هنا: http://stackoverflow.com/a/34623840/82609

slorber شكرا جزيلا على التوجيه. نتطلع إلى الأفكار القادمة هنا https://github.com/slorber/scalable-frontend-with-elm-or-redux

taggartbg هل فتحت مشكلة في النهاية؟ أنا مهتم بشيء مشابه - عند وجود جهاز توجيه رد فعل بأشجار فرعية مستقلة مختلفة ، أجد صعوبة في الحفاظ على حالة المسار السابقة أثناء التنقل إلى فرع جديد.

تضمين التغريدة

اسمحوا لي أن أبدأ بالقول إن ملحمة redux هي مشروع رائع بالرغم من وضعها فيه ، وهذا لا يحاول بأي حال من الأحوال التقليل من ذلك.

لكنني لن أستخدمه في أي من مشاريعي في حالتها الحالية. فيما يلي بعض الأسباب

الملاحم عديمة الجنسية

لا يمكنك إجراء تسلسل لحالة المولد ، فهي منطقية أثناء تشغيلها لكنها مرتبطة تمامًا بحالة الملحمة. هذا يسبب سلسلة من القيود:

  • لا يمكنك السفر عبر الزمن مولدات
  • لا يمكنك تتبع المسار الذي أدى إلى الحالة الحالية للملحمة
  • لا يمكنك تحديد حالة أولية
  • لا يمكنك فصل منطق الأعمال عن حالة التطبيق [*]
  • لا يمكنك تخزين الملاحم

[*] يمكن تفسير ذلك على أنه تعريف منطق الأعمال ضمن تعريف نموذج التطبيق ، مما يجعل الحرفين M و C في MVC نفس الشيء ، والذي يمكن اعتباره مضادًا

إجراءات الإرسال غير حتمية

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

حالة قابلة للتسلسل

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


يعد تخزين المنطق في الحالة أمرًا سيئًا ، وفي رأيي هذا ما تفعله ملحمة redux بطريقة ما.

من الجيد تمامًا افتراض أن حالة تطبيقك خاصة بتطبيقك. هذا يعني أنه من المقبول أيضًا افتراض أن حالة التطبيق يمكن التنبؤ بها طالما أنها تعمل فوق تطبيقك. هذا يعني أنه من المقبول الاحتفاظ بمعلومات المتجر التي تحدد سلوك تطبيقك دون حفظ المنطق هناك بالفعل.

تضمين التغريدة

أنا أتفهم مخاوفك. إذا نظرت إلى قضايا redux-saga ، فسترى أن هذه الأشياء تمت مناقشتها وهناك حلول يمكن العثور عليها.

لاحظ أيضًا أن redux-saga تختار التنفيذ باستخدام المولدات ، لكنها ليست مطلبًا على الإطلاق لتنفيذ نمط الملحمة ، وهناك إيجابيات وسلبيات.

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

هناك أدوات تطوير ملحمية تسمح بتتبع تنفيذ الملاحم.

هناك حلول ممكنة للسفر عبر الزمن ولكن لا يوجد تنفيذ ملموس حتى الآن

حق. موضوع طويل جدا وشيق جدا. لقد كنت أقارن مناهج مختلفة لإدارة الدولة.

أضع بعض الأشياء في الاعتبار أثناء المقارنة:

  1. مصدر واحد للحقيقة
  2. ما مدى سهولة / صعوبة العرض على جانب الخادم وتغذية البيانات الأولية من جانب العميل
  3. devtools مثل التراجع / الإعادة وتخزين السجل المستمر بعد عمليات إعادة التحميل.
  4. الرسوم المتحركة والرسوم المتحركة والرسوم المتحركة. أسأل نفسي دائمًا _ "كيف ستعمل الرسوم المتحركة مع الحل أ أو ب" _. هذا هو المفتاح بالنسبة لي لأن المنتجات التي أقوم بتطويرها تتمحور حول UX. أشارك الكثير من الارتباكات jsonnull .
  5. إعادة استخدام المكونات داخل تطبيق آخر
  6. ترطيب البيانات المرجعية (_المشكلة الكبرى _) من أجل الحفاظ على السلامة (المتعلقة بتغذية البيانات الأولية من جانب الخادم أو أي مصدر بيانات آخر)
  7. مجتمع المطورين الآخرين للمناقشة مثل هذا

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

أبرز المشاريع الأخرى التي كنت أبحث فيها هي نمط SAM (من الصعب الدخول في العقلية وعدم وجود أدوات) و Mobx (المعروف بتخزينه القابل للتغيير).

كلاهما يشتركان في فكرة مصدر واحد للحقيقة وأعتقد أنه من المثير للاهتمام أن نرى كيف يتعاملون معها.

أدى بحثي (المحدود بالطبع) حول Mobx إلى ما يلي:

  1. Mobx (تمامًا مثل Redux) يدافع عن مصدر واحد للحقيقة ولكن كفئة ذات خصائص يمكن ملاحظتها. هذا المفهوم يخلق الاختلافات مع إعادة التدفق والتدفق ككل:

    1. يدعم Mobx أيضًا المتاجر الفرعية (_متداخلة / جزء من واحد عالمي _). بالنسبة لي يبدو كثيرًا مثل تحديد مخطط من جانب العميل. إنه أمر مزعج بعض الشيء حيث من المحتمل أن يكون لديك مخطط على الخادم أيضًا. أرى أوجه تشابه مع redux-orm . AFAIK تهدف المتاجر الفرعية إلى تمريرها إلى المكونات كدعامات (وبهذه الطريقة لا يعتمد المكون على حالة التعيين إلى الدعائم أو مفتاح معين للشجرة العالمية). ومع ذلك ، فإن تمرير خاصية واحدة يكسر فكرتي عن "الخصائص" - يجب أن تكون وصفية لما يحتاجه المكون. هذا في الواقع يجعلني أفكر فيما إذا كان ذلك سيكون مشكلة إذا كان يمكن استخدام React propTypes لتحديد شكل المتجر الذي يتم تمريره. أيضًا: إن وجود مخزن ومخازن فرعية كصفوف يجعل من الممكن الرجوع إلى البيانات مباشرة دون الحاجة إلى التطبيع ، ولكن هذا نوع من العبث إذا كنت تريد تغذية البيانات الأولية بسبب:

    2. ومع ذلك ، فإن فكرة التخزين كفئة تعني أن المطور ليس لديه تسلسل خارج الصندوق ، مما يعني أن هذه هي وظيفتك إذا كنت تريد تغذية البيانات الأولية.

  2. يمكن تحقيق التاريخ والتراجع / الإعادة من خلال أخذ لقطات من الحالة بعد تغييرها. ولكن عليك أن تكتب جهاز تسلسلي ، جهاز إلغاء التسلسل بنفسك. المثال معطى هنا: https://github.com/mobxjs/mobx-reactive2015-demo/blob/master/src/stores/time.js
  3. الشيء الجيد في كتابة المسلسلات هو أنه يمكنك استبعاد الأشياء. يبدو أنه مكان جيد لتخزين البيانات غير المستمرة المتعلقة بالرسوم المتحركة. لذلك إذا قمت بتسلسلها ، فأنت تتجاهلها فقط وليس لديك إعادة / تراجع مليء بخطوات الرسوم المتحركة.
  4. يدعو Mobx إلى الاحتفاظ بمشتقات البيانات في المتجر (كطرق للتخزين) مقابل reselect + connect decorator. هذا يبدو نوعًا من الخطأ بالنسبة لي.
  5. نظرًا لطبيعته التي يمكن ملاحظتها ، فإن mobx يجعل من السهل تحديد المكونات النقية الفعالة. المقارنة الضحلة للخصائص ليست مشكلة لأن المحتويات يمكن ملاحظتها على أي حال.

بمقارنة SAM و Redux ، أود التفكير في كيفية تدفق المنطق:

  1. إعادة:

    1. حدد متجرًا

    2. تحديد الوظائف التي تتعامل مع تغييرات المتجر (المخفضات)

    3. تحديد معرفات الحدث (إجراء إعادة الإرسال) (نوع إجراء إعادة الإرسال) لكل تغيير في المتجر وتشغيل مخفض معين عندما يتطابق

    4. قم بتعيين المخزن إلى خصائص حاوية المكون ، وتمرير معالجات تفاعل المستخدم اختياريًا (النقر والكتابة والتمرير وما إلى ذلك) كوظائف تؤدي ببساطة إلى تشغيل الحدث / الإرسال.

    5. يُطلق المكون حدثًا (إجراء إعادة الإرسال) يتطابق مع جميع مخفضات السرعة

    6. عرض مع الحالة الجديدة.

  2. SAM:

    1. حدد متجرًا.

    2. حدد وظيفة الموصّل / الواضع للمخزن. يقبل هذا المُعيِّن أي بيانات ويستند فقط إلى البيانات التي يحاول تحديد مكان وضعها في المتجر وما إذا كان يحتاج إلى طلب البيانات من الخادم أو الاستمرار هناك. لا يمكن دائمًا معرفة ما يجب فعله بالبيانات بمجرد فحصها ، لذلك في بعض الأحيان يتم استخدام المعرفات / العلامات (مثل isForgottenPassword ). يهدف هذا المُعيِّن أيضًا إلى التحقق من صحة البيانات وتخزين الأخطاء بدلاً من ذلك. بعد انتهاء setter -> التقديم بالحالة الجديدة.

    3. تحديد الوظائف التي تقبل قطعة من البيانات ، وتحويلها (بديل لمخفضات إعادة الإرسال) وتنفيذ الواضع الذي يمرر البيانات المحولة. هذه الوظائف لديها الآن فكرة عن شكل المتجر. إنهم يعرفون فقط البيانات التي تم تمريرها.

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

    5. ملاحظة: لا يوجد إرسال للإجراءات ، تمرير مباشر للمخفضات.

لذلك ، كل عمليات إعادة الإرسال ، SAM و Mobx تُبقي الدولة في مكان واحد. الطريقة التي يفعلون بها ذلك ، تجلب نكساتهم الخاصة. لا أحد يستطيع التغلب على الإحياء والنظام البيئي الخاص به حتى الآن.

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

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

لا أعرف ما إذا كنتم قد قرأتم هذا المقال من إريك ميجر . مجرد اقتباس بسيط:

خلافًا للاعتقاد الشائع ، فإن جعل متغيرات الحالة غير قابلة للتغيير لا يقترب من القضاء على التأثيرات الحتمية الضمنية غير المقبولة

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

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

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

تكمن المشكلة الأساسية في هندسة البرمجيات في أن كل شخص يبدو أنه يعتقد أن التعيين هو طفرة. تدعم لغات البرمجة المهام فقط ، وتترك الطفرة لتفسير المبرمج.

إن إضافة غلاف وظيفة إلى مجموعة من التعيينات لن يصبح تلقائيًا أفضل طريقة لتغيير الحالة. هذا هراء.

هناك نظرية وراء طفرة الحالة (التطبيقية) ، تسمى TLA + ، والغريب أن إريك لم يذكر TLA + ...

JJ-

اسمحوا لي أن أوضح لأنه يبدو أن هناك الكثير من الالتباس. توضح ورقة إريك ببلاغة أن لغات البرمجة الإلزامية معطلة إلى حد ما عندما يتعلق الأمر بحالة الطفرات. أعتقد أن الجميع يوافق على ذلك.

السؤال هو كيف تبدأ وتصلحه؟ ألا توافق على أن هذا هو نوع المشكلة التي تتطلب نهج " المبدأ الأول

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

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

يمكنك أن تضحك بقدر ما تريد حول مثال إريك هاها:
// prints Ha var ha = Ha(); var haha = ha+ha;

لكن كل ما يقوله هو أنك تتخذ إجراءً خاطئًا في دولة معينة. لاأكثر ولا أقل.

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

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

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

بصراحة ، jdubray ، أنت

سأغلق الخيط في هذه المرحلة. أعتقد أن التعليقات يمكن أن تستمر ، لكن بالتأكيد لا يوجد أي شيء عملي هنا.

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

لا بأس ، ضع علامة على أنه يمكنك إزالة تعليقاتي ، فلماذا تفسد هذه المحادثة الرائعة؟

jdubray فقط أنت ترى أنها

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

توضح ورقة إريك ببلاغة أن لغات البرمجة الإلزامية معطلة إلى حد ما عندما يتعلق الأمر بحالة الطفرات. أعتقد أن الجميع يوافق على ذلك.

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

أنت حر في تجاهل TLA + ، ولكن يبدو الأمر كما لو كنت تشتكي من أنك حاولت إرسال صاروخ إلى القمر على افتراض أن الأرض كانت مسطحة وكان من الصعب حقًا توجيه سفينة الفضاء.

يبدو هذا بشكل قاطع وكأنه تشبيه وليس مبدأ أول بالتأكيد. بجدية ، هل تعتقد أن هذا البيان يعتبر "مناقشة رائعة"؟

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

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

ربما تفضل gaearon وأنشئ دروس فيديو TLA + / SAM لـ egghead. إذا كان بإمكانك شرح أفكارك بطريقة بسيطة للغاية ، في أقل من ساعتين من مقاطع الفيديو ، وفي النهاية تنقر أنماطك وتشعر بأنها مفيدة للمطورين ، فستفوز. فعل Redux ذلك لكثير من الناس. لقد "حاولت" فقط أن تشرح نظريًا سبب كون SAM / TLA + أفضل من Redux ، وقدمت تطبيق TodoMVC سيئ المظهر. نحن هنا باحثون في علوم الكمبيوتر ، نحتاج إلى مواد ملموسة. هل يمكنك أن تُظهر لنا تطبيقًا مكتوبًا بلغة Redux مقابل مكتوب بلغة SAM ، حيث سيشعر الناس بالفعل أن تطبيق SAM أفضل؟ لم يكن هذا هو الحال حتى الآن.

Niondir لقد توصلت إلى طريقة لاستخدام القصص المصورة في الحالات التي تحتاج فيها إلى استعادة حالة.
إنه يشبه إلى حد كبير نمطًا أو مجموعة قواعد يجب اتباعها

  • افصل بين القصص الملحمية بحيث لا تحتوي كل واحدة منها على أكثر من put . إذا كان لديك الملاحم التي تحتوي على أكثر من put بداخلها قم بتقسيمها وربطها بتأثير call . على سبيل المثال
function* mySaga() {
  yield put(action1());
  yield put(action2());
}

// split into

function* mySaga() {
  yield put(action1());
  yield call(myNextSaga);
}

function* myNextSaga() {
  yield put(action2());
}
  • يجب تقسيم Sagas ذات التأثيرات take إلى منطق يتبع take ونقطة بداية الملحمة. على سبيل المثال
function* mySaga() {
  yield take(ACTION);
  // logic
}

// split it into

function* rootSaga() {
  yield takeLatest(ACTION, mySaga);
}

function* mySaga() {
  // logic
}
  • قم بإنشاء نوع من ميزة "نقطة تفتيش" لكل ملحمة ، مما يعني أنه في البداية اقرأ من الولاية ومن هناك call الملحمة التي تحتاجها
function* rootSaga() {
  // emit all forks and take effects that need to run in the background
  yield call(recoverCheckpoint);
}

function* recoverCheckpoint() {
  const state = yield select();
  if (state.isFetching) {
    // run the saga that left the state like this
  }
}

يعتمد تفسير سبب نجاح هذا على مجموعة من الافتراضات التي تكون صحيحة بشكل عام

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

تقسيم الملاحم بهذه الطريقة له أيضًا بعض التأثيرات الإيجابية

  • الملاحم أكثر قابلية لإعادة الاستخدام
  • يتم تغيير الملاحم بسهولة أكبر
  • الملاحم أسهل للفهم

لكن slorber :

يجد الكثير من الأشخاص عينة "لعبة الصيد" هذه مثيرة جدًا للاهتمام بالنسبة للكود لأنها توضح بشكل مباشر كيفية عمل SAM بالكامل ، بما في ذلك تمثيل الحالة الديناميكي و "المسند الإجراء التالي". يخفف NAP من الحاجة إلى Sagas ، ولا يتطلب كسر مبدأ Redux # 1 الذي هو شجرة حالة واحدة ، ولكن ماذا أعرف؟

في بعض الأحيان عندما أستخدم Ableton Live ، تخطر ببالي فكرة "هل من الممكن كتابة Ableton Live GUI كتطبيق React / Redux؟" أعتقد أن الإجابة هي لا ، سيكون من الصعب للغاية الحصول على أداء مقبول. هناك سبب لكتابتها في Qt وسبب أن Qt لديها بنية إشارات / فتحات.

لقد كنت أستخدم React / Redux مع Meteor. أقوم بتخزين مستندات mongo في حالة Immutable.js عن طريق إرسال إجراءات Redux لعمليات رد النداء إلى Mongo.Collection.observeChanges . لقد اكتشفت مؤخرًا أنه عند الاشتراك في عدة آلاف من المستندات ، كانت واجهة المستخدم بطيئة للغاية عند بدء التشغيل نظرًا لأنه تم إرسال آلاف إجراءات Redux حيث أرسل Meteor نتائج الاشتراك الأولية واحدة تلو الأخرى ، مما تسبب في حدوث الآلاف من عمليات Immutable.js وآلاف من عمليات إعادة العرض بسرعة بقدر الإمكان. أفترض أن RethinkDB تعمل أيضًا بهذه الطريقة ، رغم أنني لست متأكدًا.

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

@ jedwards1211 لدي مشكلة مماثلة (الكثير من الرسائل الصغيرة التي من شأنها أن تكوّن البيانات الأولية).

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

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

لما يستحق ، خطرت لي فكرة إنشاء "فروع". إنه يتحدى تمامًا مبدأ المتجر الواحد ، لكنه بدا وكأنه حل وسط جيد.

https://github.com/stephenbunch/redux-branch

@ jedwards1211 أعتقد أنه مع تزايد تعقيد التطبيقات ، هناك حاجة في النهاية إلى

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

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

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

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

لذا فإن بنية الألياف تقسم التحديثات إلى حزم عمل وتجدولها وفقًا للأولوية بناءً على العمل الذي يتم تنفيذه. تعتبر الرسوم المتحركة ذات أولوية عالية - بحيث لا يتم مقاطعتها ، ويكون للتحديثات الميكانيكية الأبطأ أولوية أقل.

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

إذا كنت أقوم ببناء تطبيق معقد اليوم ، فسأبدأ بفئة متجر عالية المستوى تشبه Redux مدعومة من قبل عدد قليل من المتاجر المختلفة. بقسوة:

  • يحتوي مخزن بيانات المستوى الأعلى على قائمة انتظار للإجراءات الواردة
  • الإجراءات هي إما لإجراءات الرسوم المتحركة التي يجب إرسالها بسرعة ، أو تفاعلات التطبيق التي لها أولوية أقل
  • يتم إرسال إجراءات الرسوم المتحركة في قائمة الانتظار إلى خلفية يمكن ملاحظتها من حلقة requestAnimationFrame
  • يتم إرسال إجراءات التفاعل للإعادة عند اكتمال إجراءات الرسوم المتحركة من قائمة الانتظار

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

jsonnull لم

@ jedwards1211 هناك بضع حالات يمكنني التفكير فيها حيث لا تعمل حالة الرسوم المتحركة المحلية. سأمنحك ، إنها ليست حالات ستواجهها مع كل طلب ، لكنني أعتقد أنها تأتي كثيرًا بما يكفي.

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

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

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


الآن للحصول على مثال حيث لديك القدرة على الاحتفاظ ببعض حالة الرسوم المتحركة محلية - إنشاء لعبة متصفح مع واجهة مستخدم تعتمد على React فوقها.

  • عادة ستقود اللعبة باستخدام العلامات ... يبدأ وقت اللعبة من 0 ويزداد في كل إطار. يمكن عمل الرسوم المتحركة الأساسية للعبة على لوحة الرسم أو WebGL حيث لا توجد حالة محلية ، لذلك ستعمل على تحديد وقت بدء الرسوم المتحركة والتقدم بناءً على هذه العلامات.

على سبيل المثال: تحتوي شخصية النقش المتحرك على رسم متحرك يتكون من 10 إطارات ، وتريد تشغيل الرسم المتحرك لأكثر من 400 مللي ثانية ، لذلك ستقوم بتغيير الكائن المرسوم كل علامتين أو نحو ذلك.

يمكن أن تكون علاماتك أيضًا طوابع زمنية إذا كنت تريد دقة أعلى.

  • يمكن أيضًا أن تتوقف لعبتك مؤقتًا ، وفي هذه الحالة قد ترغب في إيقاف بعض الرسوم المتحركة التي تم إجراؤها في جانب واجهة مستخدم React.

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

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

بشكل عام ، من الأفضل أيضًا تنسيق الرسوم المتحركة عن طريق تمرير أوقات البدء / التوقف من خلال Redux والسماح للمكونات بالحفاظ على بقية الحالة محليًا.

هذا لا ينطبق فقط على الألعاب. قد يمر أي تسلسل موسع للرسوم المتحركة بهذا ، كما لو كنت تريد عمل سلسلة من الرسوم المتحركة طويلة المدى على موقع باستخدام React.

jsonnull رائع ، هذا مثال رائع ، شكرًا

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

var user = {id: 'user1', posts: [], comments: []}
var post = {id: 'post1', user: user, comments: []}
user.posts.push(post);
var comment = {id: 'comment1', post: post, user: user}
post.coments.push(comment)
user.comments.push(comment)
appState.user = user

لا يسمح Redux باستخدام التسلسلات الهرمية للكائنات مع المراجع الدائرية. في Mobx (أو Cellx) ، يمكنك ببساطة الحصول على مراجع فردية ومتعددة ومتعددة مع كائنات وتبسيط منطق الأعمال عدة مرات

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

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

var user = {id: 'user1', postIds: [], commentIds: []}
var post = {id: 'post1', userId: user.id, commentIds: []}
user.postIds.push(post.id);
var comment = {id: 'comment1', postId: post.id, userId: user.id}
post.commentIds.push(comment.id)
user.commentIds.push(comment.id)
appState.userId = user.id
appState.posts = {[post.id]: post}
appState.comments = {[comment.id]: comment}

// then join things like so:
var postsWithComments = _.map(appState.posts, post => ({
  ...post,
  comments: post.commentIds.map(id => appState.comments[id]),
})

@ jedwards1211 لاستنساخ الحالة مع وجود مراجع دائرية في الإعادة ، يجب أن يقوم المخفض بإرجاع كل نسخة جديدة من الكائن الذي تأثر بالتغييرات. إذا تغيرت الإشارة إلى الكائن ، فيجب أيضًا أن يكون الكائن المرتبط نسخة جديدة ، وسيتم تكرار ذلك بطريقة تكرارية وسيولد حالة جديدة كاملة عند كل تغيير. لا يمكن لـ Immutable.js تخزين المراجع الدائرية.
مع نهج التسوية ، عندما يحتاج بعض معالج الأحداث إلى بعض البيانات ، فإنه يتطلب في كل مرة أخذ الكائن بمعرفه من الحالة العامة. على سبيل المثال - أحتاج إلى تصفية أشقاء المهام في مكان ما في معالج الحدث (يمكن أن يكون للمهام هيكل هرمي) مع redux ، أحتاج إلى إرسال thunk للوصول إلى حالة التطبيق

var prevTask = dispatch((_, getState)=>getState().tables.tasks[task.parentId]).children.map(childId=>dispatch((_, getState)=>getState().tables.tasks[childId])).filter(task=>...) [0]

أو مع المحددات

var prevTask = dispatch(getTaskById(task.parentId)).children.map(childId=>dispatch(getTaskById(childId)).filter(task=>...)[0]

وهذا النموذج المتداول يحول الكود إلى فوضى مقارنة بإصدار mobx عندما يمكنني الكتابة ببساطة

var prevTask = task.parent.children.filter(task=>...)[0]

@ jedwards1211 ، bgnorlov : FWIW ، هذا هو أحد الأسباب التي Redux-ORM . يسمح لك بالحفاظ على متجر Redux الخاص بك طبيعيًا ، ولكنه يجعل إجراء تلك التحديثات وعمليات البحث العلائقية أسهل. في الواقع ، هذا المثال الأخير مطابق بشكل أساسي لـ Redux-ORM.

لقد كتبت للتو مدونتين تصفان أساسيات Redux-ORM ، بالإضافة إلى المفاهيم الأساسية والاستخدام المتقدم .

@ markerikson رائع ، شكرًا على النصيحة!

تضمين التغريدة

شيء واحد يجب ملاحظته هو أننا لا ننوي استخدام Redux لجميع الحالات. فقط كل ما يبدو مهمًا للتطبيق. أود أن أزعم أنه يجب معالجة المدخلات وحالة الرسوم المتحركة بواسطة React (أو أي تجريد آخر للحالة المؤقتة). يعمل Redux بشكل أفضل مع أشياء مثل البيانات التي تم جلبها والنماذج المعدلة محليًا.

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

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

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

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

bgnorlov هذه نقطة جيدة أنه من المستحيل تخزين المراجع الدائرية باستخدام Immutable.js ، لم أفكر في ذلك مطلقًا! أعتقد أنها ميزة جميلة رغم ذلك.

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

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

FWIW ، تشير المستندات إلى أنه ليس كل شيء يجب أن يذهب إلى Redux ، حسب http://redux.js.org/docs/faq/OrganizingState.html#organizing -state-only-redux-state.

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

كما هو الحال دائمًا ، إذا كان لدى الأشخاص أفكار لتحسين المستندات ، فإن PRs مرحب بهم تمامًا :)

إذا احتجت في أي وقت إلى إعادة استخدام المخفضات والقدرة على تخصيص "حالات فرعية" في حالة إعادة التشغيل ، فقد قمت بتطوير مكون إضافي للقيام بذلك دون عناء (مع تكامل React)

https://github.com/eloytoro/react-redux-uid

eloytoro IMO إذا كنت تواجه مشكلة مع بعض القابل لإعادة الاستخدام نمط الخالق.

eloytoro كنت سأكتب شيئًا

@ jedwards1211 أعتقد أنك فهمت الفكرة الخاطئة. لم أذكر مخفضات الطرف الثالث أو مشاكل معهم بأي شكل من الأشكال ، فقط أحاول عرض كيف يمكن لمقتطفي حل المشكلة لجعل المخفضات قابلة لإعادة الاستخدام في مجموعات ذات أحجام ديناميكية

avesus نأمل أن يعمل من أجلك

eloytoro آه ، هذا منطقي أكثر.

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

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

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

@ mib32 قد تكون على حق! نأمل أن يعتاد الناس في النهاية على صياغة رسوم متحركة جيدة في React.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات

القضايا ذات الصلة

rui-ktei picture rui-ktei  ·  3تعليقات

captbaritone picture captbaritone  ·  3تعليقات

timdorr picture timdorr  ·  3تعليقات

dmitry-zaets picture dmitry-zaets  ·  3تعليقات

ilearnio picture ilearnio  ·  3تعليقات