Redux: لم يتم استدعاء mapStateToProps ()

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

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

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

اسمحوا لي أن أقول أولاً ما _فعل _:

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

لكن ... لم أجد وصفًا لكيفية ارتباط الإجراءات والمخفضات و mapStateToProps ببعضها البعض. أسئلتي:

  • أعتقد أن المتجر كائن ، له خصائص تحتوي على بيانات حول حالة التطبيق. يمكن أن تكون خصائص المستوى الأعلى كائنات توفر شجرة فرعية للاحتفاظ بمعلومات حول جزء من التطبيق. هل هذا صحيح؟
  • عندما يتم إرسال إجراء إلى المتجر ، ما الخاصية (أو الشجرة الفرعية للمتجر) التي يتم تحديثها؟ يبدو أن هناك إنشاءًا تلقائيًا / ارتباطًا بخاصية داخل المتجر ، ولكن كيف يتم تحديد ذلك؟
  • كيف "تعرف" mapStateToProps للاستماع إلى التحديثات على الممتلكات / الجزء المناسب من المتجر؟ ما الذي يربط بينهما؟
  • كيف يمكنني تصحيح هذا؟ ما الذي يجب أن أفعله لمعرفة لماذا لا يبدو أن إرسال الإجراء يؤدي إلى إطلاق خريطةStateToProps؟
  • أم أفكر في الأمر كله خطأ ...؟
question

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

هل مررت بـ http://redux.js.org/docs/Troubleshooting.html وتحققت من أن حالتك ليست واحدة من المشكلات التي تصفها؟

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

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

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

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

إذا كان مخفض الجذر الخاص بك هو وظيفة كتبتها بنفسك ، فإن نتيجتها هي ما ستحصل عليه بعد إرسال إجراء:

function counter(state = 0, action) {
  if (action.type === 'INCREMENT') {
    return state + 1; // will become the next value of store.getState() after store.dispatch()
  }
  return state;
}

إذا قمت بإنشاء مخفض الجذر بشيء مثل combineReducers({ foo, bar }) ، فسيكون كما لو كنت قد كتبت مخفض الجذر يدويًا يشبه هذا:

function root(state = {}, action) {
  return {
    foo: foo(state.foo, action),
    bar: bar(state.bar, action)
  }
}

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

كيف "تعرف" mapStateToProps للاستماع إلى التحديثات على الممتلكات / الجزء المناسب من المتجر؟ ما الذي يربط بينهما؟

يمكنك تمرير mapStateToProps إلى الوظيفة connect() . يقوم بإنشاء مكون يستخدم store.subscribe() للاستماع إلى كل تغيير في المتجر. عندما يتغير المتجر ، يقرأ المكون الذي تم إنشاؤه store.getState() ويمرره إلى mapStateToProps() لتحديد العناصر التالية المراد تمريرها. إذا تغيروا ، فسيتم إعادة تقديم المكون الخاص بك معهم.

كيف يمكنني تصحيح هذا؟ ما الذي يجب أن أفعله لمعرفة لماذا لا يبدو أن إرسال الإجراء يؤدي إلى إطلاق خريطةStateToProps؟

أضف برمجية وسيطة مثل https://github.com/theaqua/redux-logger. تحقق من أن الحالة يتم تحديثها بعد الإجراء بالطريقة التي تتوقعها. إذا لم يتم استدعاء mapStateToProps ، فهذا يعني ذلك

  • إما أنك نسيت أن تقوم بإجراء dispatch() واتصلت للتو بمنشئ إجراء ،
  • أو أرجع المخفض قيمة مماثلة مرجعية لذلك لم يكلف connect() عناء استدعاء mapStateToProps() .

تم وصف كلتا الحالتين في http://redux.js.org/docs/Troubleshooting.html.

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

شكر!

ال 4 كومينتر

هل مررت بـ http://redux.js.org/docs/Troubleshooting.html وتحققت من أن حالتك ليست واحدة من المشكلات التي تصفها؟

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

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

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

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

إذا كان مخفض الجذر الخاص بك هو وظيفة كتبتها بنفسك ، فإن نتيجتها هي ما ستحصل عليه بعد إرسال إجراء:

function counter(state = 0, action) {
  if (action.type === 'INCREMENT') {
    return state + 1; // will become the next value of store.getState() after store.dispatch()
  }
  return state;
}

إذا قمت بإنشاء مخفض الجذر بشيء مثل combineReducers({ foo, bar }) ، فسيكون كما لو كنت قد كتبت مخفض الجذر يدويًا يشبه هذا:

function root(state = {}, action) {
  return {
    foo: foo(state.foo, action),
    bar: bar(state.bar, action)
  }
}

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

كيف "تعرف" mapStateToProps للاستماع إلى التحديثات على الممتلكات / الجزء المناسب من المتجر؟ ما الذي يربط بينهما؟

يمكنك تمرير mapStateToProps إلى الوظيفة connect() . يقوم بإنشاء مكون يستخدم store.subscribe() للاستماع إلى كل تغيير في المتجر. عندما يتغير المتجر ، يقرأ المكون الذي تم إنشاؤه store.getState() ويمرره إلى mapStateToProps() لتحديد العناصر التالية المراد تمريرها. إذا تغيروا ، فسيتم إعادة تقديم المكون الخاص بك معهم.

كيف يمكنني تصحيح هذا؟ ما الذي يجب أن أفعله لمعرفة لماذا لا يبدو أن إرسال الإجراء يؤدي إلى إطلاق خريطةStateToProps؟

أضف برمجية وسيطة مثل https://github.com/theaqua/redux-logger. تحقق من أن الحالة يتم تحديثها بعد الإجراء بالطريقة التي تتوقعها. إذا لم يتم استدعاء mapStateToProps ، فهذا يعني ذلك

  • إما أنك نسيت أن تقوم بإجراء dispatch() واتصلت للتو بمنشئ إجراء ،
  • أو أرجع المخفض قيمة مماثلة مرجعية لذلك لم يكلف connect() عناء استدعاء mapStateToProps() .

تم وصف كلتا الحالتين في http://redux.js.org/docs/Troubleshooting.html.

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

شكر!

الرد بالترتيب:

  • تفترض Redux بشكل عام أن الجزء العلوي من شجرة الولاية هو كائن Javascript عادي (على الرغم من أنه من الشائع أيضًا استخدام أنواع البيانات التي توفرها مكتبة Immutable.js). ما تضعه داخل هذا الكائن وكيف تقوم ببناء المحتويات متروك لك تمامًا. الطريقة الأكثر شيوعًا هي تنظيم الأشياء حسب المجال. على سبيل المثال ، قد تبدو شجرة الحالة لتطبيق مدونة افتراضي بالشكل التالي: { users : {}, posts : {}, comments : {}, ui : {} } . راجع http://redux.js.org/docs/FAQ.html#reducers -share-state و http://redux.js.org/docs/FAQ.html#organizing -state-nested-data.
  • من الناحية الفنية ، عند إنشاء متجرك ، فإنك تحدد وظيفة "مخفض" _ واحد. يتم استدعاء هذه الوظيفة بالحالة الحالية والإجراء الوارد ، وتكون مسؤولة عن إرجاع كائن حالة جديد ، مع _ all_ التحديثات المناسبة ، والتي تتم بطريقة غير قابلة للتغيير (على سبيل المثال ، لا توجد تعديلات مباشرة في المكان - يجب أن يكون كل ما يحتاج إلى التحديث يتم ذلك عن طريق عمل نسخ وتعديلها وإعادة النسخ بدلاً من ذلك ، وتحديث حقل متداخل يعني أيضًا نسخ وتحديث جميع أسلافه). ومع ذلك ، نظرًا لأن وضع كل جزء أخير من منطق التحديث في وظيفة عملاقة واحدة يعد فكرة سيئة ، فإن منطق التحديث هذا ينقسم دائمًا تقريبًا إلى وظائف مخفض فرعية أصغر قابلة لإعادة الاستخدام. إن كيفية هيكلة هذا المنطق أمر متروك لك مرة أخرى ، ولكن لا يتم تحديث أي شيء تلقائيًا - الأمر متروك لمنطق المخفض للقيام بذلك. تجعل الأداة المساعدة combineReducers التي تأتي مع Redux من السهل الحصول على وظيفة مخفض محددة تكون مسؤولة عن إدارة التحديثات لشريحة معينة من البيانات ، مثل: const combinedReducer = combineReducers({users : userReducer, posts : postReducer, comments : commentsReducer, ui : uiReducer});
  • يقوم Redux ببساطة بإعلام جميع المشتركين عندما يتم تنفيذ أي إجراء من خلال المتجر. تشترك وظيفة React Redux connect() ، ثم تستدعي المكون mapStateToProps لمعرفة ما إذا كان أي من البيانات المستخرجة قد تغير منذ آخر مرة. لا يوجد اشتراك محدد للولاية المتداخلة. راجع http://redux.js.org/docs/FAQ.html#store -setup-subscriptions.
  • السبب الأول لعدم تحديث المكون هو حدوث طفرة مباشرة في الحالة في المخفض. راجع http://redux.js.org/docs/FAQ.html#react -not-rerendering. علاوة على ذلك ، هناك عدد من الوظائف الإضافية التي يمكنك استخدامها لتصحيح وتسجيل الإجراءات. لدي مجموعة منهم مدرجة في https://github.com/markerikson/redux-ecosystem-links/blob/master/devtools.md.

نأمل أن يساعد ذلك في توضيح الأمور.

أبعد من ذلك ، كما قال دان: تعتبر أسئلة الاستخدام أكثر ملاءمة بشكل عام لـ Stack Overflow. أيضًا ، لدى مجتمع Reactiflux على Discord مجموعة من قنوات الدردشة المخصصة للتقنيات المتعلقة بـ React ، بما في ذلك Redux ، وهناك دائمًا عدد من الأشخاص يتجولون على استعداد للإجابة على الأسئلة. يوجد رابط دعوة على https://www.reactiflux.com .

@ richb-hanover ربما تكون قد شاهدت المقارنة السطحية التي يتم إجراؤها بواسطة وصلة رد الفعل والإعادة. هذا يعني أن الكائنات المتداخلة ضمن كائنات أخرى لن تؤدي إلى إعادة عرضها حتى إذا تم تعديلها لأنه يتم فحص مفتاح الجذر فقط من أجل التعديلات.

http://redux.js.org/docs/faq/ReactRedux.html#why -isnt-my-component-re-rendering-or-my-mapstatetoprops-running

@ richb-hanover في حالتي ، اكتشف gaearon المشكلة:

أو أعاد المخفض قيمة مماثلة مرجعية ، لذا لم يكلف connect () عناء استدعاء mapStateToProps ().

كنت أستخدم هذا الإصلاح وكان هذا هو الرمز الناتج

const mapStateToProps = (state, props) => {
    return { id: props.id, currentState: state[props.id] };
}

const mapDispatchToProps = (dispatch) => {
    return {
        increment: (id) => {
            dispatch({ type: 'INCREMENT', id: id })
        }
    }
}

const DumbListItem = ({
    increment,
    id,
    currentState
}) => (
        <div>
            <li onClick={() => increment()}>{id}</li>
            <span>{currentState}</span>
        </div>
    );

export const ConnectedListItem = connect(
    mapStateToProps,
    mapDispatchToProps
)(DumbListItem);

نظرًا لأنني لم أمرر المعلمة id لاستدعاء الزيادة (إما increment(id) في القالب ، أو عبر المعلمة الثانية في mapDispatchToProps ) ، فإن المتجر لم يفعل التحديث بشكل صحيح ، لذا تحقق مما إذا كانت هذه هي مشكلتك.

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