简体   繁体   English

使用 redux 和 react 的异步服务器端渲染

[英]Async server-side rendering using redux & react

I am having serious difficulty getting a working server-side rendering solution using React , Redux , Redux-Thunk and React-Router .我在使用ReactReduxRedux-ThunkReact-Router获得有效的服务器端渲染解决方案时遇到了严重的困难。

At the moment, my solution works on the client-side following the basic guidelines and this post: https://codepen.io/stowball/post/a-dummy-s-guide-to-redux-and-thunk-in-react .目前,我的解决方案在客户端遵循基本准则和这篇文章: https : //codepen.io/stowball/post/a-dummy-s-guide-to-redux-and-thunk-in-反应 For the scope of simplicity, I will be using the code from that blog as my example.为简单起见,我将使用该博客中的代码作为示例。 The only alteration is that I have added a console.log("X");唯一的改变是我添加了一个console.log("X"); to the reducer function items so that I know when it is called.到减速器功能items以便我知道何时调用它。 The resultant function is:结果函数是:

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

        default:
            return state;
    }
}

and I also set the itemsFetchData function to return the promise, becoming:我还设置了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)));
    };
}

As I need server-side rendering.因为我需要服务器端渲染。 I setup Express to consume my middleware handleRender which in turn calls renderFullPage that returns the HTML string.我设置 Express 来使用我的中间件handleRender ,它反过来调用返回 HTML 字符串的renderFullPage The Express implementation can be assumed correct.可以假定 Express 实现是正确的。 My handleRender looks like the below我的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));
  });
}

Using the above code, Y is printed to the console, but X is never printed, meaning the reducer function is not being called.使用上面的代码, Y被打印到控制台,但X永远不会被打印,这意味着没有调用 reducer 函数。 If I remove the then from the promise in my handleRender, thus becoming:如果我从我的 handleRender 中的承诺中删除then ,从而变成:

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

The reducer function is being called correctly and the Redux store updated correctly, however since this is asynchronous the handleRender would have returned the HTML already. reducer 函数被正确调用并且 Redux 存储正确更新,但是由于这是异步的, handleRender将已经返回 HTML。

Any help would be greatly appreciated.任何帮助将不胜感激。 It's been a long day.这是漫长的一天。

The source of the confusion was caused because the reducer was injected after the itemsFetchData was called.造成混乱的根源是因为在调用itemsFetchData之后注入了itemsFetchData The problem was only noted when using then because without it, the component Main which injected the reducer was still included and everything seemed normal.使用时,问题只是指出then ,因为没有它,成分Main其注入减速仍包括在内,似乎一切正常。 When it was relying on the then I ended up with the then unable to dispatch because there was no reducer and the Main component not included because it was waiting for the dispatch.当它依托then我结束了与then无法调度,因为没有减速和Main部件不包括在内,因为它在等待调度。

To solve the problem, I have included the reducer in my combineReducers .为了解决这个问题,我在我的combineReducers包含了 reducer。

Like I said, it was a long day.就像我说的,这是漫长的一天。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM