Я уже некоторое время пытаюсь реализовать рендеринг на стороне сервера для приложения Redux / React. Я настроил все в соответствии с примерами, которым следовал, но происходит что-то странное.

Когда я смотрю на процесс рендеринга на шкале времени Google Chrome, я заметил, что мой html отображается на долю секунды, затем он исчезает, а затем снова отображает все с нуля (вроде как он игнорировал мой контент на стороне сервера, когда React пытался смонтировать к нему, а затем просто использовал обычный рендеринг на стороне клиента).

Я проверил, что отправлено клиенту, и вроде все в порядке. Все теги html, head и javascript для назначения окну присутствуют. Кроме того, когда он изначально пытается визуализировать html со стороны сервера, он выглядит хорошо в течение этой доли секунды (я проверил временную шкалу Chrome и просмотрел покадровые изображения того, что он отображает).

Мне интересно, видно ли что-нибудь сразу из следующей установки или каких-либо идей о том, что может происходить. Ниже приводится своего рода псевдокод, показывающий, что я реализовал. Я отредактирую, если для каких-либо комментариев потребуется дополнительный код или информация.

// 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>
    }
}
0
kjonsson 6 Сен 2016 в 18:35

3 ответа

Лучший ответ

Я наконец понял, в чем дело. Если вы используете асинхронные маршруты с require.ensure, вам нужно вызвать match перед рендерингом на стороне клиента:

match({ history, routes }, (err, redirectLocation, renderProps) => {
    render(
        <Provider store={store}>
            <Router history={history} routes={routes}/>
        </Provider>,
        document.getElementById('main')
    );
});
0
kjonsson 7 Сен 2016 в 11:11

Я создал стартер для реагирования на рендеринг на стороне сервера. Он был построен с использованием рекомендаций Redux и React-Router v4. Пожалуйста, проверьте это

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

0
Zoreslav Goral 27 Дек 2017 в 14:51

Если ваш клиентский код рендерится снова, это означает, что рендеринг вашего сервера отличается от рендеринга клиента, поэтому ваш клиентский код просто очищает все и снова рендерит.

Вот что я делаю. Просто используйте свой локальный bundle.js, чтобы заменить bundle.min.js для отладки приложения, и вы должны найти предупреждение о react markup checksum, и просто сравните то, что ваш сервер отображает и ваш клиентский рендер, посмотрите в чем разница.

Моя проблема в том, что на моем сервере есть свойство data-react-id. поэтому я использую ReactDom.renderToStaticMarkup для замены ReactDom.renderToString. вы можете сначала попробовать.

0
chenkehxx 7 Сен 2016 в 06:36