React: Server-side rendering and async routing

Created on 31 Oct 2017  路  6Comments  路  Source: facebook/react

Hi!

When I render a synchronous route on server-side and then the client side hydrate the dom, I get a warning because client side asynchronous route doesn't find the component.

image

In other hand react fiber reconciliation tries to remove this non hydratable node. So the page makes a blank flash on client side :(

image

Most helpful comment

This pattern has never worked correctly. In React 15 it would still blow away your server rendered markup and replace it on the client.

The solution is to render the same thing both on the client and the server side (just like before). If you're using Promises on the client side, you need to wait for them to resolve before doing hydration. This is not an easy problem, but it's outside of scope of React. Projects like https://github.com/thejameskyle/react-loadable can help you with handling this correctly.

All 6 comments

image

According to this screenshot, the generated node from server side rendering will be remove. This node (div.home-page) is a dynamic component of the current route

How can I tell the reconciler to not remove this node, because it will be hydrated by the dynamic imported corresponding component?

Some code snippets for more explanations

Routes definition

import {
  HomePage,
} from '../bundles/Bundles';

export default [
  {
    component: HomePage,
    path: '/',
    exact: true,
    strict: true,
  },
];

The Bundles.js used on server side

export const HomePage = syncComponent('HomePage', require('../views/HomePage/HomePage'));

The AsyncBundles.js used on client side

export const HomePage = asyncComponent('HomePage', () => Promise.all([
  import('../views/HomePage/HomePage' /* webpackChunkName: 'HomePage' */),
  importCss('HomePage'),
]));

Thanks to the NormalModuleReplacementPlugin webpack plugin I'm able to switch from Bundles.js and AsyncBundles.js for server and client rendering

     new webpack.NormalModuleReplacementPlugin(/Bundles\.js/, 'AsyncBundles.js'),

HomePage.js component renders a simple div

<div className="home-page">Home Page</div>

The main Wrapper.js that renders the routes

      <Route
        render={({ location }) => (
          <div className="app__wrapper">
            <Switch location={location}>
              {routes.map((route, index) => (
                <Route
                  key={route.path}
                  path={route.path}
                  exact={route.exact}
                  render={route.component}
                />
              ))}
              <Route
                key={'not found'}
                path={'*'}
                render={NotFound}
              />
            </Switch>
          </div>
        )}
      />

The html generated on server-side looks like this:

<div class="app__wrapper">
  <div class="home-page">
    Home Page
  </div>
</div>

When I open the chrome debugger timeline, I get a flashing blank frame
image

Before the blank frame, it's the rendered html, after it's the chunked HomePage.123456.js that is rendered

That is fiber warning on client side: Did not expect server HTML to contain div.home-page in div.app__wrapper ... and removes it before rendering the exact same dynamic imported HomePage.js

This pattern has never worked correctly. In React 15 it would still blow away your server rendered markup and replace it on the client.

The solution is to render the same thing both on the client and the server side (just like before). If you're using Promises on the client side, you need to wait for them to resolve before doing hydration. This is not an easy problem, but it's outside of scope of React. Projects like https://github.com/thejameskyle/react-loadable can help you with handling this correctly.

Thanks! I am looking at another one https://github.com/ctrlplusb/react-async-component

Was this page helpful?
0 / 5 - 0 ratings

Related issues

zpao picture zpao  路  3Comments

jvorcak picture jvorcak  路  3Comments

varghesep picture varghesep  路  3Comments

hnordt picture hnordt  路  3Comments

framerate picture framerate  路  3Comments