Я пытаюсь сделать 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
видеть, что необходимо для визуализации разметки головы.Но, надеюсь, нет проблем с моим подходом двухпроходного рендеринга?