使用renderToString和renderToNodeStream反应SSR两遍渲染

时间:2019-01-02 16:00:06

标签: javascript reactjs styled-components ssr react-helmet

我正在尝试对ReactDOMServer.renderToNodeStream(element)进行SSR,但只是想知道在每次请求时同时使用ReactDOMServer.renderToString(element)ReactDOMServer.renderToNodeStream(element)是否会有问题?

我的自定义SSR设置中有: *反应16 *可加载 *样式化组件v4 *反应头盔异步 * Redux * Express JS

以前使用React,我可以通过首先渲染包含<head></head>产生的标记的react-helmet标签,然后使用ReactDOMServer.renderToString()渲染我的React元素来轻松渲染HTML文档。

但是,通过切换到ReactDOMServer.renderToNodeStream(),我不得不将react-helmet的{​​{1}}切换为支持react-helmet-async功能的renderToNodeStream()。但是,当我尝试用<head></head>标记呈现react-helmet-async标签时,它将返回为undefined

要解决此问题,我必须首先使用renderToString(),而不必将其实际写到Express JS response中。这样,react-helmet-async可以看到要渲染的元标记,然后继续使用renderToNodeStream并将其流式传输到response

我已经尽可能地简化了我的代码,以了解这是否会对性能产生负面影响(对于性能,还是任何人都可以想到的东西)?

之前:

let html = ReactDOMServer.renderToString(stylesheet.collectStyles(
    <Loadable.Capture report={moduleName => modules.push(moduleName)}>
        <LocalStoreProvider store={store}>
            <HelmetProvider context={helmetContext}>
                <RouterContext {...renderProps} />
            </HelmetProvider>
        </LocalStoreProvider>
    </Loadable.Capture>
));

const { helmet } = helmetContext; 

response.write(
    renderDocumentHead({
        css: stylesheet.getStyleTags(),
        title: helmet.title.toString(),
        link: helmet.link.toString(),
        meta: helmet.meta.toString()
    })
);

response.write(html);

之后:

let html = stylesheet.collectStyles(
    <Loadable.Capture report={moduleName => modules.push(moduleName)}>
        <LocalStoreProvider store={store}>
            <HelmetProvider context={helmetContext}>
                <RouterContext {...renderProps} />
            </HelmetProvider>
        </LocalStoreProvider>
    </Loadable.Capture>
);

// do a first pass render so that react-helmet-async 
// can see what meta tags to render
ReactDOMServer.renderToString(html);

const { helmet } = helmetContext; 

response.write(
    renderDocumentHead({
        css: stylesheet.getStyleTags(),
        title: helmet.title.toString(),
        link: helmet.link.toString(),
        meta: helmet.meta.toString()
    })
);

const stream = stylesheet.interleaveWithNodeStream(
    ReactDOMServer.renderToNodeStream(html)
);

// and then actually stream the react elements out
stream.pipe(response, { end: false });

stream.on('end', () => response.end('</body></html>'));

不幸的是,只有使react-helmet-async正常工作的唯一方法,我必须进行两次遍历渲染。我的CSS样式等可以正确解析,并且客户端也可以正确渲染/水合。我还看到了其他示例,其中使用了react-apollo并且使用了getDataFromTree数据补水方法,该方法允许react-helmet-async查看呈现头部标记所需的内容。但是希望我的两遍渲染方法没有问题吗?

0 个答案:

没有答案