使用redux& amp;的异步服务器端渲染反应

时间:2017-10-17 15:38:46

标签: javascript reactjs redux react-router redux-thunk

使用ReactReduxRedux-ThunkReact-Router获取正常工作的服务器端渲染解决方案时遇到了严重困难。

目前,我的解决方案在客户端遵循基本准则和帖子:https://codepen.io/stowball/post/a-dummy-s-guide-to-redux-and-thunk-in-react。为了简单起见,我将使用该博客中的代码作为我的示例。唯一的变化是我在减速器函数console.log("X");中添加了items,以便我知道它何时被调用。结果函数是:

export function items(state = [], action) {
    switch (action.type) {
        case 'ITEMS_FETCH_DATA_SUCCESS':
            console.log('X');
            return action.items;

        default:
            return state;
    }
}

我还设置itemsFetchData函数以返回承诺,成为:

export function itemsFetchData(url) {
    return (dispatch) => {
        dispatch(itemsIsLoading(true));

        return fetch(url)
            .then((response) => {
                if (!response.ok) {
                    throw Error(response.statusText);
                }

                dispatch(itemsIsLoading(false));

                return response;
            })
            .then((response) => response.json())
            .then((items) => dispatch(itemsFetchDataSuccess(items)))
            .catch(() => dispatch(itemsHasErrored(true)));
    };
}

因为我需要服务器端渲染。我设置Express以使用我的中间件handleRender,后者又调用返回HTML字符串的renderFullPage。可以假设Express实现是正确的。我的handleRender如下所示

export function handleRender(req, res) {
  // Create a new Redux store instance
  const store = configureStore();

  const { dispatch } = store;

  dispatch(itemsFetchData(''http://5826ed963900d612000138bd.mockapi.io/items'')).then(() => {
    console.log("Y");
    // Render the component to a string
    const html = renderToString(
      <Provider store={store}>
        <div id="app">
          <StaticRouter context={{}} location={req.url}>
            <Main />
          </StaticRouter>
        </div>
      </Provider>
    );

    // Grab the initial state from our Redux store
    const preloadedState = store.getState();

    // Send the rendered page back to the client
    res.send(renderFullPage(html, preloadedState));
  });
}

使用上面的代码,Y将打印到控制台,但永远不会打印X,这意味着不会调用reducer函数。如果我从handleRender中的promise中删除then,从而成为:

dispatch(itemsFetchData(''http://5826ed963900d612000138bd.mockapi.io/items''));
console.log("Y");
// ... remaining code remains unaltered

正确调用reducer函数并正确更新Redux存储,但由于这是异步的,因此handleRender已经返回了HTML。

非常感谢任何帮助。这是漫长的一天。

1 个答案:

答案 0 :(得分:1)

引起混淆的原因是因为在调用itemsFetchData 之后注入了reducer。只有在使用then时才会发现问题,因为没有它,注入reducer的组件Main仍然包含在内,一切似乎正常。当它依赖于then我最终导致then无法发送,因为没有减速器且Main组件未包括在内,因为它正在等待发送。

要解决这个问题,我已将减速器包含在我的combineReducers

就像我说的那样,这是漫长的一天。