【问题标题】:Redux - Loading initial state asynchronouslyRedux - 异步加载初始状态
【发布时间】:2016-09-20 11:06:45
【问题描述】:

我正在尝试找出最简洁的方法来加载来自 API 调用的 Redux 存储的初始状态。

我了解提供初始状态的典型方式是在页面加载时在服务器端生成它,并将其作为简单对象提供给 Redux createStore()。但是,我正在编写一个应用程序,打算用 Electron 打包,所以这行不通。

到目前为止,我能想到的最好方法是在创建商店后立即触发一个操作,该操作将去请求商店的初始状态 - 一个操作可以检索整个初始状态,或者一个操作每个操作检索存储的一部分的初始状态的操作数。这意味着我的代码看起来像:

const store = createStore(reducer, Immutable.Map(), middleware);
store.dispatch(loadStateForA());
store.dispatch(loadStateForB());
store.dispatch(loadStateForC());

虽然这会起作用,但它似乎有点粗略,所以我想知道是否有更好的选择我错过了?

【问题讨论】:

  • 真的有必要在启动时加载所有数据吗?您可以根据访问的页面加载部分吗?

标签: javascript redux flux


【解决方案1】:

我也遇到了同样的问题(也在构建一个电子应用程序)。我商店的一部分有应用程序设置,这些设置保存在本地文件系统上,我需要在应用程序启动时异步加载它。

这就是我想出的。作为 React/Redux 的“新手”,我非常有兴趣了解社区对我的方法的看法以及如何改进它。

我创建了一个异步加载存储的方法。此方法返回一个包含store 对象的Promise

export const configureStoreAsync = () => {
  return new Promise((resolve) => {
    const initialState = initialStoreState;//default initial store state
    try {
        //do some async stuff here to manipulate initial state...like read from local disk etc. 
        //This is again wrapped in its own Promises.
        const store = createStore(rootReducer, initialState, applyMiddleware(thunk));
        resolve(store);
      });
    } catch (error) {
      //To do .... log error!
      const store = createStore(rootReducer, initialState, applyMiddleware(thunk));
      console.log(store.getState());
      resolve(store);
    }
  });
};

然后在我的应用程序入口点,我是这样使用它的:

configureStoreAsync().then(result => {
  const store = result;
  return ReactDOM.render(
    <Provider store={store}>
      <App store={store}/>
    </Provider>,
    document.getElementById('Main'));
});

就像我说的,这是我解决这个问题的幼稚尝试,我相信一定有更好的方法来处理这个问题。我很想知道如何改进这一点。

【讨论】:

    【解决方案2】:

    据我所知,您只有两个选择(逻辑上):

    1. 商店实例化后设置初始状态
    2. 设置初始状态商店被实例化

    选项 1必须使用动作完成:

    改变状态的唯一方法是发出一个动作,一个对象 描述发生了什么。

    ——One of "Three Principles" in the docs

    这是您尝试过的方法,但出于某种原因您认为它很粗糙。


    另一种方法是在您的异步请求解决后调用createStore。已经使用Promise 对象发布了一个解决方案(@Gaurav Mantri),这是一个不错的方法。

    我建议不要这样做,因为您可能会有多个模块在您的商店(或store.dispatch,或store.subscribe)存在之前尝试requireimport;他们都必须期待Promises。第一种方法是最 Redux-y 的。

    【讨论】:

      【解决方案3】:

      我的应用启动工作流程:

      1. 在 index.html 中加载微调器
      2. Ajax 检查用户是否登录
      3. 在 ajax 端,渲染 Root 组件
      4. 隐藏加载微调器

      我通过以下方式实现了这一目标:

      1. 使用自定义中间件创建商店,该中间件侦听初始 ajax 结束操作并调用一次回调
      2. 调度初始 ajax 操作

      root.js

      const store = createStore(
          rootReducer,
          applyMiddleware(
              ...,
              actionCallbackOnceMiddleware(INITIAL_AJAX_END, render)
          )
      )
      
      function render() {
          ReactDOM.render(
              <Provider store={store}>
                  <RootComponent/>
              </Provider>,
              document.getElementById('root')
          )
      
          document.getElementById('loading').dispatchEvent(new Event('hide'))
      }
      
      store.dispatch(initialAjaxAction());
      

      middleware/actionCallbackOnce.js

      export default (actionType, callback) => store => next => {
          let called = false;
      
          return action => {
              next(action);
      
              if (!called && action.type === actionType) {
                  called = true;
                  callback();
              }
          }
      }
      

      index.html

      <div id="loading">
          <span>Loading</span>
          <style type="text/css">...</style>
          <script>
              (function(loading){
                  loading.addEventListener('hide', function(){
                      loading.remove();
                  });
                  loading.addEventListener('error', function(){
                      loading.querySelector('span').textContent = "Error";
                  });
              })(document.getElementById('loading'));
          </script>
      </div>
      
      <div id="root"></div>
      

      【讨论】:

        【解决方案4】:

        extraReducerscreateAsyncThunk 一起使用似乎是一种干净的方式,正如here 所解释的那样

        【讨论】:

          猜你喜欢
          • 2016-09-22
          • 1970-01-01
          • 2019-01-29
          • 2020-11-26
          • 1970-01-01
          • 1970-01-01
          • 2018-08-25
          • 2016-08-27
          相关资源
          最近更新 更多