服务器端渲染反应

时间:2016-09-06 15:35:03

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

我一直在尝试为Redux / React应用程序实现服务器端呈现。我根据我所遵循的例子设置了所有内容但却发生了一些奇怪的事情。

当我查看Google Chrome时间轴中的渲染过程时,我注意到我的html显示了一瞬间,然后它消失了,然后它再次从头开始呈现所有内容(有点像它在React时忽略了我的服务器端内容试图挂载到它然后只使用正常的客户端渲染)。

我已经检查了发送给客户端的内容,看起来没问题。所有的html,head标签和分配给窗口的javascript都在那里。此外,当它最初尝试从服务器端渲染html时,它看起来很适合那一瞬间(我在Chrome时间轴中检查并查看了渲染内容的逐帧图像。)

我想知道从以下设置或任何想法可能发生的事情是否立即显而易见。以下是一种伪代码,显示了我实现的内容。如果任何评论需要更多代码或信息,我会编辑。

// client - configureStore and configureRoutes are custom 
// functions that just return the store with initial state and the routes.
const serverState = JSON.parse(window._SERVERSTATE);
const store = configureStore(browserHistory, serverState);
const history = syncHistoryWithStore(browserHistory, store);
const routes = configureRoutes(store);

render(
    <Provider store={store}>
        <Router history={history} routes={routes}/>
    </Provider>,
    document.getElementById('main')
);
// server - node.js
const initialState = setupState();
const memoryHistory = createMemoryHistory(req.url);
const store = configureStore(memoryHistory, initialState);
const history = syncHistoryWithStore(memoryHistory, store);
const routes = configureRoutes(store);

match({ history, routes, location: req.url }, (err, redirectLocation, renderProps) => {

    if (err) {
        return next(err)
    }

    if (redirectLocation) {
        return res.redirect(302, redirectLocation.pathname + redirectLocation.search)
    }

    // Fetches all data need to render components by calling their static initializeActions functions
    fetchData(store.dispatch, renderProps.components, renderProps.params)
        .then(() => {

            const body = renderToString(
                <Provider store={store}>
                    <RouterContext {...renderProps} />
                </Provider>
            );

            const helmetHeaders = Helmet.rewind();

            const state = JSON.stringify(store.getState());

            const html = `
                <!DOCTYPE html>
                <html>
                    <head>
                        ${helmetHeaders.title.toString()}
                        <link rel="stylesheet" type="text/css" href="/styles.css">
                    </head>
                    <body>
                        <div id="main">
                            ${body}
                        </div>
                        <script> 
                            window._SERVERSTATE = ${JSON.stringify(state)}
                        </script>
                        <script src="/app.js"></script>
                    </body>
                </html>
        })
})
// Typical component
class Example extends React.Component{
    static initializeActions = [ ExampleAction ]

    render() {
        <div>Hello</div>
    }
}

3 个答案:

答案 0 :(得分:0)

如果您的客户端代码再次呈现,则表示您的服务器呈现与客户端呈现不同,因此您的客户端代码只清除所有内容并再次呈现它。

以下是我的操作,只需使用您的本地bundle.js替换您的bundle.min.js来调试您的应用,您应该找到关于react markup checksum的警告,然后比较一下您的服务器渲染和你的客户端渲染,看看有什么区别。

我的问题是我的服务器上有data-react-id属性。所以我使用ReactDom.renderToStaticMarkup来替换ReactDom.renderToString。你可以先试试。

答案 1 :(得分:0)

我终于弄清楚出了什么问题。如果您使用require.ensure的异步路由,则必须在呈现客户端之前调用匹配:

match({ history, routes }, (err, redirectLocation, renderProps) => {
    render(
        <Provider store={store}>
            <Router history={history} routes={routes}/>
        </Provider>,
        document.getElementById('main')
    );
});

答案 2 :(得分:0)

我已经为反应服务器端渲染创建了启动器。它是使用redux和react-router v4的建议构建的。请检查出来

https://github.com/gzoreslav/react-redux-saga-universal-application