Redux: المكونات التي لا يتم إعادة عرضها باستخدام connect ()

تم إنشاؤها على ٢٠ أغسطس ٢٠١٥  ·  32تعليقات  ·  مصدر: reduxjs/redux

لقد تعرفت على Redux من خلال قراءة المستندات وبدأت فقط في تعديل مثال العالم الحقيقي. في حالتي ، قمت بتبديل استدعاءات GitHub HTTP API بمفاهيمي الخاصة ، واستبدلت مفاهيم Repo و User بأخرى مماثلة في بيئتي. حتى الآن ، لا ينبغي أن تكون مختلفة جدًا ، أليس كذلك؟

هنا حيث أواجه مشكلة:

نجحت مكالمات API الخاصة بي ، واستجابة JSON أصبحت على شكل camelCased وتطبيعها ، _ ولكن_ لا يتم إعادة عرض المكون الخاص بي بعد حدوث طلب API بنجاح. بعد وقت قصير من إرسال USER_REQUEST وإظهار تحديثات مكون المستخدم "جارٍ التحميل ..." ، يتم إرسال USER_SUCCESS ، ولا تحتوي حالته التالية على مفتاح entities مأهول:

pasted_image_8_19_15__3_27_pm

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

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

شكرا جزيلا!

question

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

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

لذلك سأفحص مخفضاتك بالتأكيد وأتأكد من أنك لا تغير الحالة الحالية. امل ان يساعد!

ال 32 كومينتر

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

لذلك سأفحص مخفضاتك بالتأكيد وأتأكد من أنك لا تغير الحالة الحالية. امل ان يساعد!

بالإضافة إلى ما قاله ernieturner ، تأكد من أن الوظيفة mapStateToProps في دالة connect(mapStateToProps)(YourConnectedComponent) تعين الحالة ذات الصلة (في هذه الحالة entities ) بحيث يستمع المكون المتصل لتلك الشريحة من الدولة.

ضع في اعتبارك أيضًا أن connect() يقوم بإجراء مقارنة ضحلة: https://github.com/rackt/react-redux/blob/d5bf492ee35ad1be8ffd5fa6be689cd74df3b41e/src/components/createConnect.js#L91

من المحتمل أنه نظرًا لأن شكل حالة الاتصال الخاصة بك لم يتغير ، فمن المفترض عدم إجراء تحديث.

آه ، حسنًا! كان mapStateToProps يحاول استخراج كائن من الحالة ، لكن لم يكن يحدد المفتاح الصحيح. بدلاً من استخراج entities.users[login] ، قمت بتعيينه على entities.users[id] . و entities.users كان مرتبطا الكائن login سلسلة، وذلك عندما الرقمية id ولم يوجد أي الدعائم تغير الواقع، لذلك لا إعادة تقديم هناك حاجة.

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

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

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

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

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

قد يكون من المفيد توضيح أن الاتصال في الأماكن السفلية من الشجرة ليس ضروريًا تمامًا لحل مشكلة المقارنة العميقة.

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

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

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

const reducers = combineReducers({
    //...bunch of reducers which always return objects of 3 or 4 properties that change sometimes but
    // the shape stays the same
    dataVersion: (state = Symbol(), action = {}) => {
        switch (action.type) {
            case SAME_ACTION_AS_THE_ONE_THAT_UPDATES_A_COMPLEX_PROPERTY:
            case ANOTHER_ACTION_THAT_ALSO_UPDATES_A_COMPLEX_PROPERTY:
                return Symbol():
            default:
                return state;
        }
    }
})

لا يزال هذا يبدو غريبًا بالنسبة لي. إذا كان لدي مخفض يعمل:

    switch (action.type) {
       case UPDATE_THIS:
           return {a: action.a, b: action.b, c: action.c};
       default:
           return state;
     }

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

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

Zacqary تتم مقارنة الحالة الحالية بالحالة السابقة باستخدام مساو صارم (===). تتم مقارنة stateProps (نتيجة mapStateToProps) بمساواة ضحلة.

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

mapStateToProps هو "تجميع" البيانات الخاصة بالمكون المتصل من خلال الوصول إلى المتجر.

يسحب mapStateToProps قطعًا مختلفة من المتجر ، ويخصصها لمفاتيح في كائن جديد stateProps .

سيصبح الكائن stateProps الناتج جديدًا في كل مرة (لذلك تتغير هويته) ، لذلك لا يمكننا مقارنة هوية الكائن للكائن stateProps نفسه --- نحن _ يجب أن ننزل واحدًا المستوى وتحقق من هوية الكائن لكل قيمة ، حيث يلعب دور shallowEqual ، كما قال jimbolla .

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

يجب أن تكون حقيقة أنني أعيد كائنًا تمت تهيئته حديثًا ويكون بنفس الشكل مثل الحالة السابقة كافية لتشغيل حالة سابقة! == newState.

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

هل هناك شيء محدد لا يعمل بالشكل الذي تتوقعه؟ لست متأكدًا حقًا مما تقصده بحلك Symbol .

يجدر النظر فيما إذا كان يجب نقل المكون الإضافي إلى المكوِّن connected() ليرث الخاصيات. لقد وصلت إلى هذه المشكلة بمحاولة الحصول على مكونين connect() ، لكن هذا كان تعقيدًا غير ضروري.

ernieturner أعلم أن هذا قديم ولكن قد ترغب في تحديث رابط قسم استكشاف الأخطاء وإصلاحها .

في صحتك

لدي هذه المشكلة ، حسناً ليس بالضبط.
قمت بتطبيق الخصائص على الحالة ، مثل:

  constructor(props){
    this.state = {
      text: props.text
    }
  }

ولم يكن يعمل. لذلك قمت بتطبيق القيمة مباشرة من الدعائم مثل

{this.props.text}

ويعمل على ما يرام :)

AlexanderKozhevin ما لم أكن مخطئًا ، فقد المنشئ الخاص بك super(props) .
في العادة لا يُسمح لك باستخدام this قبل الاتصال بـ super(props) .

@ cdubois-mh على حق ، شكرًا للملاحظة.

لقد كتبت مخفض جذر التطبيق المخصص وحصلت على هذه المشكلة.
إعادة نسخة من الدولة بأكملها
{...state}
في نهاية مخفض الجذر ساعدني

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

إذا لم تقم بإرجاع نسخة ، فلن يكون رد الفعل قادرًا دائمًا على اكتشاف تغيير القيمة.
(على سبيل المثال ، إذا قمت بتعديل إدخال متداخل)

تحقق من هذه الحالة:

{
    "clients": [
        { "name": "John", "cid": 4578 },
        { "name": "Alex", "cid": 5492 },
        { "name": "Bob",  "cid": 254 }
    ]
}

إذا قمت بتعديل اسم العميل ، ولكنك لم تُرجع نسخة من الحالة ، فإنك لم تعدل الحالة ، بل قمت بتعديل الكائن في المصفوفة.

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

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

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

تحديث بالقوة

<AfterConnect
    _forceUpdate={Symbol()}
/>

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

CedSharp ستعود الدالة الضحلةEqual false ، إذا قمنا بتعيين _forceUpdate = {Symbol ()}

BrookShuihuaLee سيكون رائعًا إذا كان بإمكانك تضمين تفسير مثل هذا في إجابتك الأولى ، وبهذه الطريقة

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

BrookShuihuaLee : تبدو هذه فكرة سيئة. لماذا تريد أن تفعل ذلك؟

BrookShuihuaLee ، أتفق مع markerikson .
هناك سبب يفترض عدم إعادة نسخة عندما لم تتغير الحالة. ما لم تتمكن من تقديم مثال صالح يبدو فيه الحل الخاص بك ضروريًا ، فإنني أوصي بشدة بعدم الالتفاف حول كيفية عمل Redux.

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

BrookShuihuaLee ، أنا آسف ، ولكن ما مدى صلة المكون الخاص بك بالمناقشة المطروحة؟
إذا فهمت بشكل صحيح ، فأنت تتحدث عن المكون المخصص الخاص بك؟ ForceUpdate هو شيء محبط بشدة في عالم React ولن أوصي به كحل.

بدلاً من ذلك ، يمكنك استخدام حل يمكن ملاحظته حيث تبحث عن التغييرات في مكان آخر غير الدولة؟ لا أعرف لماذا تحتاج إلى إعادة تصيير هذا المكون المحدد دون تعديل حالته ، ولكن إذا كنت تعرف سبب إعادة تصييرها ، فربما يمكنك استخدام شيء مثل mobx؟
(https://github.com/mobxjs/mobx)

أحاول أن أفهم ما هو الحل الخاص بك ، ولماذا ينطبق في هذه الحالة.

CedSharp لا أعني أنه يجب على الجميع استخدام ForceUpdate. لكن التوصية شيء والخيار شيء آخر. تحتفظ React أيضًا بـ ReactComponent.prototype.forceUpdate للمطورين. الناس بحاجة إلى خيارات.

كنت أحاول إعطاء خيار آخر. ربما ليس الخيار الأفضل.

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

case SOME_ACTION:
      return {
        ...state,
        ts: (new Date).getTime(),
      };

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

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

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

كانت مشكلتي وجود كائن به مصفوفات. نظرًا لأنها كانت مقارنة ضحلة ، فإنها لم تصل أبدًا إلى العناصر الموجودة داخل المصفوفات التابعة. لقد قمت بحلها باستخدام list:state.obj.list بدلاً من lists:state.obj في mapStateToProps 👍🏼

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

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

تحقق من TYPOS في المخفض الخاص بك! :)

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