我应该如何在 react-router 转换期间更新 redux 存储? [英] How should I update redux store during a react-router transition?

查看:73
本文介绍了我应该如何在 react-router 转换期间更新 redux 存储?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了一个关于如何在 react-router 转换发生时更新 store 的问题.

I'm facing an issue on how to update store when a react-router transition occurs.

在我当前的实现中(如下),在渲染下一页之前更新存储.当当前页面根据下一页的数据获取商店更新时,问题就出现了:(1) 当前页面毫无意义地呈现(它订阅了商店更新),因为更新的商店是针对下一页的 (2)渲染时当前分页符,因为更新的存储只有下一页的数据.

In my current implementation (below), update store before rendering next page. The issue comes up when the current page gets a store update based on the data for the next page: (1) the current page renders pointlessly (it's subscribed to store updates), because the updated store is for the next page (2) the current page breaks on render because updated store only has data for the next page.

superagent
  .get(opts.path)
  .set('Accept', 'application/json')
  .end((err, res) => {
    let pageData = res && res.body || {};
    store.dispatch(setPageStore(pageData));
    render(store);
  });

反过来也有问题,在更新商店之前渲染下一页.现在的问题是渲染时的下一页中断,因为下一页所需的数据在商店更新之前不存在.

The reverse is problematic too, render next page before updating store. The issue now is the next page breaks on render because the data needed for the next page is not there until store is updated.

我要么滥用了库,要么我的架构不完整,或者其他原因.帮助!

I'm either misusing the libraries, or my architecture is incomplete, or something else. help!

示例代码的其余部分:

const React = require('react');
const Router = require('react-router');
const {createStore} = require('redux');
const {update} = React.addons;
const routes = require('./routes'); // all the routes
let store = {};
let initialLoad = true;

Router.run(routes, Router.HistoryLocation, (Handler, opts) => {
  if(initialLoad) {
    initialLoad = false;

    // hydrate
    const initialState = JSON.parse(document.getElementById('initial-state').text);
    store = createStore(appReducer, initialState);
    render(store);

  } else {
    superagent
      .get(opts.path)
      .set('Accept', 'application/json')
      .end((err, res) => {
        let pageData = res && res.body || {};
        store.dispatch(setPageStore(pageData));
        render(store);
      });
  }
});

function render(store) {
  React.render(
    <Provider store={store} children={() => <Handler/>} />, 
    document.getElementById('react')
  );
}

行动与减速机

function appReducer(state = {}, action) {
  switch(action.type) {
    case 'SET_PAGE_STORE':
      return update(state, {$merge: action.pageData});

    default:
      return reduce(state, action);
  }
}

const reduce = combineReducers({
  // ..all the reducers
});

function setPageStore(pageData) {
  return {type: 'SET_PAGE_STORE', pageData};
}

推荐答案

您可以使用 redux-thunk 一个接一个分派多个动作的中间件

You can use redux-thunk middleware to dispatch multiple actions one after another

查看精彩的 redux doc #Async Actions 部分了解更多!

See the awesome redux doc #Async Actions section for more!

因此,您的获取数据操作创建者将如下所示:

So your fetch data action creator will look something like this:

function fetchSomeData(path) {
  return dispatch => {
    // first dispatch a action to start the spinner
    dispatch(fetchStarted(path))

    return superagent.get(path)
      .set('Accept', 'application/json')
      .end((err, res) => {
        if (err) {
          dispatch(fetchDataError(err)) // handle error
        } else {
          let pageData = res && res.body || {};
          dispatch(fetchSuccess(pageData)); // do whatever you want when fetch is done here
          // such as this action from redux-simple-router to change route
          dispatch(pushPath('/some/path'))
      });
  }
}

如您所见,通过简单地执行 store.dispatch(fetchSomeData('somePath')),它会自动首先调用 fetchStarted 以显示微调器,当过程完成,调用fetchSuccess(path)隐藏spinner,更新状态,重新渲染...等,或者调用fetchError(err)显示错误信息,你在这个过程中的任何地方都可以调用动作来改变路线!

As you can see, by simply doing store.dispatch(fetchSomeData('somePath')), it will automatically first call fetchStarted to show spinner, and when the process is done, call fetchSuccess(path) to hide spinner, update state, rerender...etc, or call fetchError(err) to show an error message, and you can call actions to change routes anywhere in this process!

(如果不喜欢的话,不需要redux-simple router,可以调用history.pushState(null, '/some/path')来改变路由,我只是发现 redux-simple-router 真的很方便,因为你不需要到处传递历史记录,而且你有一个 UPDATE_PATH 动作,如果你想跟踪路由变化,你可以监听)

(you don't need redux-simple router if you don't like it, you can call history.pushState(null, '/some/path') to change route, I just found redux-simple-router really handy, because you don't need to pass the history everywhere, plus you have a UPDATE_PATH action you can listen to if you want to track route changes)

此外,当您使用 react- 时,我推荐 redux-simple-router带有 redux 的路由器,它允许您使用 UPDATE_PATH 操作类型和 pushPath 操作来观察路由更改以更改路由.另外,我注意到您使用的是过时版本的 react-router...

Furthermore, I recommend redux-simple-router when you use react-router with redux, it allows you to watch route changes with the UPDATE_PATH action type, and pushPath action to change route. Also, I notice you're using an out-dated version of react-router...

如果你想使用最新版本的 react-router 和 redux-simple-router(连同 redux-thunk),查看这个仓库

If you want to use the latest version of react-router with redux-simple-router (together with redux-thunk), check out this repo!

您可以在这些文件中找到它的商店配置、路由器设置:

you can find its store configuration, router setup in these files:

src/main.js                 // calls reactDOM.render(<Root />, ...) to render <Root />
src/containers/Root.js      // <Root /> is a wrapper for react-redux <Provider />
src/redux/configureStore.js // store configuration, how redux-thunk middleware is configured
src/routes/index.js         // routes are defined here

这篇关于我应该如何在 react-router 转换期间更新 redux 存储?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆