Search code examples
javascriptreactjswebpackreact-routerreact-fiber

Use hydrate() with async. components


The application I'm working on is based on React Fiber and React Router V3.

Trying to use hydrate() instead of render() with async components I've faced with the following issue: HTML returned from SSR is different from client-side one.

As a result React remounts the whole DOM and throws the following warning: Did not expect server HTML to contain....

React Training does not provide solution as well: Code-splitting + server rendering

Is there any solution to achieve this?

Updates:

Simple Example

(pseudo code)

App.js:

export default () => <div>Lorem Ipsum</div>;

client.js:

const createRoutes = store => ({
  path: '/',
  getComponent(nextState, cb) {
    require('./App'); // some async require
  },
  onEnter: (nextState, replace, cb) => {
    store.dispatch(fetchData())
      .then(() => cb())
      .catch(cb);
  }
});

match({history, routes: createRoutes(store)},
  (error, redirectLocation, renderProps) => {
  hydrate(
    <Router history={history} routes={createRoutes(store)} />,
    document.getElementById('app')
  );
});

server.js

match({routes: createRoutes(store), location: req.url},
  (err, redirectLocation, renderProps) => {
  const content = renderToString(<RouterContext {...renderProps}/>);
  // send content to client
});

Solution

  • I've been investigated the issue a bit more deeper and found the solution. To achieve DOM hydration the following point should be token in account:

    1. I the example above in client.js I invoked createRoutes(store) twice. This is redundant because renderProps already has routes property prepared for <Route /> component. Due to this mistake onEnter was called twice, so data fetching was performed twice too.

    2. To avoid HTML mismatch on server and client side data fetching in onEnter should not be called on the first client-side render.

    3. match function waits for getComponent callback is performed before render. So the main question is wrong, because this functionality is available out of the box.