Redux: إطلاق الإجراءات استجابة لتحولات المسار في جهاز التوجيه التفاعلي

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

اهلا ياجماعة،

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

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

 @connect(state => ({
   campaigngroups: state.jobresults.campaigngroups,
   error: state.jobresults.error,
   loading: state.jobresults.loading
 }))

في الوقت الحالي ، أستخدم طريقة دورة الحياة componentWillReceiveProps للرد على تغييرات عنوان url القادمة من جهاز التوجيه المتفاعل حيث أن جهاز التوجيه المتفاعل سيمرر الدعائم الجديدة إلى المعالج عندما يتغير عنوان url في this.props.params و this.props.query - المشكلة الرئيسية في هذا الأسلوب هي أنني أقوم بإطلاق إجراء في هذه الطريقة لتحديث الحالة - والتي تنتقل بعد ذلك وتمرر الدعائم الجديدة المكون الذي سيؤدي إلى تشغيل نفس طريقة دورة الحياة مرة أخرى - لذلك بشكل أساسي إنشاء لا نهاية لها loop ، حاليًا أقوم بتعيين متغير حالة لمنع حدوث ذلك.

  componentWillReceiveProps(nextProps) {
    if (this.state.shouldupdate) {
      let { slug } = nextProps.params;
      let { citizenships, discipline, workright, location } = nextProps.query;
      const params = { slug, discipline, workright, location };
      let filters = this._getFilters(params);
      // set the state accroding to the filters in the url
      this._setState(params);
      // trigger the action to refill the stores
      this.actions.loadCampaignGroups(filters);
    }
  }

هل هناك نهج قياسي لبدء الإجراءات الأساسية على انتقالات المسار أو هل يمكنني ربط حالة المتجر مباشرةً بحالة المكون بدلاً من تمريره عبر الدعائم؟ لقد حاولت استخدام الطريقة الثابتة willTransitionTo ولكن ليس لدي وصول إلى this.props.dispatch هناك.

docs ecosystem question

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

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

الحيلة هي إنشاء نوع إجراء يتم تنشيطه كلما تغير موقع جهاز التوجيه. هذا سهل في الإصدار 1.0 القادم من React Router:

// routeLocationDidUpdate() is an action creator
// Only call it from here, nowhere else
BrowserHistory.listen(location => dispatch(routeLocationDidUpdate(location)));

الآن ستكون حالة متجرك دائمًا متزامنة مع حالة جهاز التوجيه. يعمل هذا على إصلاح الحاجة إلى الرد يدويًا على تغييرات معلمات الاستعلام و setState() في المكون أعلاه - فقط استخدم Redux's Connector.

<Connector select={state => ({ filter: getFilters(store.router.params) })} />

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

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

للقيام بذلك في Redux ، قم أولاً بإنشاء تسلسل يمكن ملاحظته لحالات المتجر. يمكنك القيام بذلك باستخدام observableFromStore() redux-rx.

import { observableFromStore } from 'redux-rx';
const state$ = observableFromStore(store);

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

const didLogin$ = state$
  .distinctUntilChanged(state => !state.loggedIn && state.router.path === '/login')
  .filter(state => state.loggedIn && state.router.path === '/login');

didLogin$.subscribe({
   router.transitionTo('/success');
});

هذا التنفيذ أبسط بكثير من نفس الوظيفة التي تستخدم أنماطًا حتمية مثل componentDidReceiveProps() .

امل ان يساعد!

ال 26 كومينتر

deowk يمكنك مقارنة this.props بـ nextProps لمعرفة ما إذا تم تغيير البيانات ذات الصلة. إذا لم يتغير ، فلن تضطر إلى تشغيل الإجراء مرة أخرى ويمكنك الهروب من الحلقة اللانهائية.

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

deowk إذا كنت تستخدم بيانات غير قابلة للتغيير ، يمكنك فقط مقارنة المراجع

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

الحيلة هي إنشاء نوع إجراء يتم تنشيطه كلما تغير موقع جهاز التوجيه. هذا سهل في الإصدار 1.0 القادم من React Router:

// routeLocationDidUpdate() is an action creator
// Only call it from here, nowhere else
BrowserHistory.listen(location => dispatch(routeLocationDidUpdate(location)));

الآن ستكون حالة متجرك دائمًا متزامنة مع حالة جهاز التوجيه. يعمل هذا على إصلاح الحاجة إلى الرد يدويًا على تغييرات معلمات الاستعلام و setState() في المكون أعلاه - فقط استخدم Redux's Connector.

<Connector select={state => ({ filter: getFilters(store.router.params) })} />

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

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

للقيام بذلك في Redux ، قم أولاً بإنشاء تسلسل يمكن ملاحظته لحالات المتجر. يمكنك القيام بذلك باستخدام observableFromStore() redux-rx.

import { observableFromStore } from 'redux-rx';
const state$ = observableFromStore(store);

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

const didLogin$ = state$
  .distinctUntilChanged(state => !state.loggedIn && state.router.path === '/login')
  .filter(state => state.loggedIn && state.router.path === '/login');

didLogin$.subscribe({
   router.transitionTo('/success');
});

هذا التنفيذ أبسط بكثير من نفس الوظيفة التي تستخدم أنماطًا حتمية مثل componentDidReceiveProps() .

امل ان يساعد!

نحتاج هذا في مستندات جديدة. حسن الكتابة.

acdlite : شكرًا جزيلاً لك ، لقد ساعدتني

أريد تشغيل منشئ الإجراء في طريقة willTransitionTo الثابتة لأن هذا يبدو الخيار الوحيد في جهاز التوجيه التفاعلي v0.13.3

class Results extends Component  {
..........
}

Results.willTransitionTo = function (transition, params, query) {
 // how do I get a reference to dispatch here?
};

deowk تخميني هو أنك تتصل بـ dispatch مباشرة على نسخة redux:

const redux = createRedux(stores);
BrowserHistory.listen(location => redux.dispatch(routeLocationDidUpdate(location)));

deowk أقوم حاليًا بإرسال تغييرات عنوان url الخاص بي في جهاز التوجيه التفاعلي 0.13.3 مثل هذا:

Router.run(routes, Router.HistoryLocation, function(Handler, locationState) {
   dispatch(routeLocationDidUpdate(locationState))
   React.render(<Handler/>, appEl);
});

acdlite شرح جيد حقا! : +1:
توافق على أنه يجب أن يكون في المستندات الجديدة أيضًا :)

تمامًا كملاحظة ، تم تغيير BrowserHistory.history() إلى BrowserHistory.addChangeListener() .

https://github.com/rackt/react-router/blob/master/modules/BrowserHistory.js#L57

تعديل:

والتي قد تبدو كالتالي:

history.addChangeListener(() => store.dispatch(routeLocationDidUpdate(location)));

وماذا عن الحالة الأولية لهذا المخفض ، @ pburtchaell؟

لدي الإعداد التالي:

// client.js
class App extends Component {
  constructor(props) {
    super(props);
    this.history = new HashHistory();
  }

  render() {
    return (
      <Provider store={store}>
         {renderRoutes.bind(null, this.history)}
      </Provider>
    );
  }
}

// routes.js
export default function renderRoutes(history) {

  // When the route changes, dispatch that information to the store.
  history.addChangeListener(() => store.dispatch(routeLocationDidUpdate(location)));

  return (
    <Router history={history}>
      <Route component={myAppView}>
        <Route path="/" component={myHomeView}  />
      </Route>
    </Router>
  );
};

يؤدي هذا إلى تنشيط منشئ الإجراء routeLocationDidUpdate() كل مرة يتغير فيها المسار وعندما يتم تحميل التطبيق في البداية.

pburtchaell هل يمكنك مشاركة routeLocationDidUpdate ؟

تضمين التغريدة إنه صانع عمل.

// actions/location.js
export function routeLocationDidUpdate(location) {
  return {
    type: 'LOCATION_UPDATE',
    payload: {
      ...location,
    },
  };
}

pburtchaell ، لذلك في

إليك نسخة كاملة من المثال أعلاه:

https://github.com/acdlite/redux-react-router/blob/master/README.md#bonus -reacting-to-state-Changes-with-redux-rx

أفترض أن pburtchaell سيستخدم

<strong i="7">@connect</strong>

للدخول ، دعنا نقول في

<Comments />

الذي سيكون بالفعل "متصل" (مشترك) بمخزن التعليقات؟ أو فقط أضف تسجيل إجراءات الموقع هذه في commentsStore؟

عنوان url مثل

/comments/123

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

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

نظرًا لوجود إشارة إلى dispatch ضمن السياق ، فإنني أفكر أن أنظف طريقة للحصول على هذا للاتصال من جانب العميل fetchData هو مكون يشبه Connector يستدعي fetchData أو shouldFetchData ، أو احصل على مرجع لرد الاتصال select مع dispatch مع state ، حتى نتمكن من فحص التيار حالة store وإرسال الإجراءات FETCH كما هو مطلوب.

هذا الأخير أكثر إيجازًا ولكنه يكسر حقيقة أن select يجب أن يظل وظيفة خالصة. سأبحث في السابق.

الحل الخاص بي هو هذا ، على الرغم من أنه مصمم تمامًا للإعداد الخاص بي (طريقة fetchData(dispatch, state) الثابتة التي ترسل إجراءات غير متزامنة _FETCH ) ، إلا أنها ستستدعي أي عمليات استرجاع تم تمريرها إليها بالخصائص المناسبة: https: // gist.github.com/grrowl/6cca2162e468891d8128 - لا تستخدم willTransitionTo ، على الرغم من ذلك ، لذلك لن تتمكن من تأخير نقل الصفحات.

نحن بالتأكيد بحاجة إلى إضافة المستندات! ممكن في قسم "الاستخدام مع جهاز التوجيه التفاعلي".

سيكون لدينا طريقة رسمية للقيام بذلك بعد إصدار 1.0.

من الرائع سماعgaearon.

ثم الأمر يتعلق فقط باستخدام مشغلين يمكن ملاحظتهم للاشتراك في تغييرات حالة معينة.

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

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

تحرير: Ack! آسف ، أجبت على سؤالي الخاص. رمز زائف أدناه. اسمحوا لي أن أعرف إذا كان يبدو فظيعا؟

const didChangeProject$ = state$
  .distinctUntilChanged(state => state.project._id)
  .filter(state => typeof state.project._id !== 'undefined');

الإغلاق لصالح # 177. عندما نصل إلى توثيق التوجيه ، سنحتاج إلى تغطية جميع السيناريوهات: إعادة التوجيه عند تغيير الحالة ، وإعادة التوجيه عند الطلب ، وما إلى ذلك.

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

حتى يكون هناك برنامج تعليمي ، لا تتردد في إلقاء نظرة على examples/real-world الذي يحتوي على التوجيه. إنها ليست "الأحدث والأعظم" في الوقت الحالي ولكنها تعمل بشكل جيد.

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