简体   繁体   English

服务器端渲染React

[英]Server Side Rendering React

I've been trying to implement server side rendering for a Redux/React application for a while now. 一段时间以来,我一直在尝试为Redux / React应用程序实现服务器端渲染。 I've set everything up according to the examples that I followed but something weird is happening. 我已经按照示例进行了所有设置,但是正在发生一些奇怪的事情。

When I look at the rendering process in the Google Chrome timeline I noticed that my html shows up for a split second, then it disappears and then it renders everything from scratch again (sort of like it ignored my server side content when React tried to mount to it and then just used normal client side rendering). 当我在Google Chrome浏览器时间轴中查看渲染过程时,我注意到我的html出现了一秒钟,然后消失了,然后再次从头开始渲染所有内容(就像当React尝试挂载时,它忽略了我的服务器端内容一样)然后使用普通的客户端渲染)。

I've checked what is sent over to the client and it seems to be fine. 我已经检查了发送给客户端的内容,这似乎很好。 All the html, head tags and the javascript to assign to the window is there. 分配给窗口的所有html,head标签和javascript都在那里。 Also when it initially tries to render the html from the server side it looks good for that split second (I checked in Chrome timeline and looked at frame by frame images of what it is rendering). 同样,当它最初尝试从服务器端渲染html时,它看起来很适合瞬间(我在Chrome浏览器时间轴中进行了检查,并逐帧查看了其渲染的图像)。

I'm wondering if anything is immediately apparent from the following setup or any ideas what might be going on. 我想知道从下面的设置或任何想法可能会立即发现什么。 The following is sort of pseudocode showing what I implemented. 以下是一种伪代码,显示了我实现的内容。 I'll edit if any of the comments need more code or info. 如果有任何评论需要更多代码或信息,我将进行编辑。

// 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>
    }
}

if your client code render again, it means what your server render is different from client render, so your client code just clear everything and render it again. 如果您的客户端代码再次渲染,则意味着您的服务器渲染与客户端渲染不同,因此您的客户端代码只需清除所有内容并再次渲染即可。

Here is What I do, just use your local bundle.js to replace your bundle.min.js to debug your appliaction, and you should find a warning about react markup checksum , and just compare what your server render and your client render, see what is the difference. 这是我的工作,只需使用本地的bundle.js替换您的bundle.min.js来调试应用程序,然后您将发现有关react markup checksum的警告,并仅比较服务器渲染结果和客户端渲染结果,请参见有什么区别。

my problem is there are data-react-id property on my server. 我的问题是服务器上有data-react-id属性。 so I use ReactDom.renderToStaticMarkup to replace ReactDom.renderToString . 所以我用ReactDom.renderToStaticMarkup代替ReactDom.renderToString you can try it first. 您可以先尝试。

I finally figured out what was wrong. 我终于弄清楚了什么地方出了问题。 If you are using async routes with require.ensure then you have to call match before rendering client side: 如果您使用带有require.ensure的异步路由,则必须在呈现客户端之前调用match:

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

I've created starter for react server-side rendering. 我已经创建了用于响应服务器端渲染的启动器。 It was built using off recommendations from redux and react-router v4. 它是根据redux和react-router v4的建议构建的。 Please check it out 请检查一下

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

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

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