Реагируйте на два прохода рендеринга SSR с помощью renderToString и renderToNodeStream
Я пытаюсь сделать SSR с ReactDOMServer.renderToNodeStream(element)
но просто хотел знать, будут ли какие-либо проблемы с использованием обоих ReactDOMServer.renderToString(element)
а также ReactDOMServer.renderToNodeStream(element)
на каждый запрос?
То, что у меня есть в моей пользовательской настройке SSR: * React 16 * реагирующая загрузка * styleled-компоненты v4 * реагирующий-шлем-асинхронный * Redux * Express JS
Ранее с React я мог легко визуализировать HTML-документ, сначала отобразив <head></head>
теги, содержащие разметку, созданную react-helmet
а затем с помощью ReactDOMServer.renderToString()
сделать мои элементы React.
Однако, переключаясь на ReactDOMServer.renderToNodeStream()
Я должен был переключиться react-helmet
за 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
чтобы увидеть, что нужно сделать для разметки головы. Но, надеюсь, нет проблем с моим подходом двухпроходного рендеринга?