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

0 ответов

Другие вопросы по тегам