Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SSR: dynamic import in react app how to deal with html miss match when component is loading on the client

I'm just starting on server side rendering a react 16 app using code splitting and dynamic import thanks to webpack 4 and react-loadable.

My question might sound stupid but there's something I don't quite get.

On the server side, I'm waiting that webpack has loaded all modules before spitting out the html to the client.

On the client side I have a kind of loading component rendered, before rendering the loaded component.

So basically the server renders the loaded component:

<div>loaded component</div>

And the client hydrates the loading component:

<div>loading...</div>

Obviously, The problem is that React complains after hydrate() because there is a miss match between server and client.

During a few seconds the client first renders

<div>loading...</div>

whereas server has rendered and sent to the client, the html of the loaded component.

Can someone enlighten me ? how does it work exactly ? How can I prevent a mismatch at first render when the component is being loaded ?

like image 675
jaybe78 Avatar asked Nov 07 '18 18:11

jaybe78


People also ask

How do I import component dynamically into React?

In React, dynamically importing a component is easy—you invoke React. lazy with the standard dynamic import syntax and specify a fallback UI. When the component renders for the first time, React will load that module and swap it in.

What is fallback in React?

The fallback prop accepts any React elements that you want to render while waiting for the component to load. You can place the Suspense component anywhere above the lazy component. You can even wrap multiple lazy components with a single Suspense component.

Does useEffect run on SSR?

Another caveat of SSR is that useEffect and useLayoutEffect hooks, by design, do not run on when rendering.


1 Answers

Looks like you're not preloading the assents in you client.

Loadable.preloadReady().then(() => {
  ReactDOM.hydrate(<App/>, document.getElementById('app'));
});

This is also a required step to avoid the hydration mismatch.

Reason:

This issue is caused on your client because the initial request, your chunks were not loaded, so the html output for those components would be loading... instead of the component content itself. Only after the chunks are fetched and loaded that this initial state loading... will be replaced by the desired content.

So, Loadable.preloadReady method creates a Promise that will be resolved once the application chunks were preloaded, in that way, having all assets needed for the initial stage, ReactDOM.hydrate will generate the same output as your server did.


TIP

Also I recommend you to take a look at React Loadable SSR Add-on, it is a very handy add-on that will enhance your server side assets management, giving you the same benefits as it was CSR (Client Side Render).

Server Side Render add-on for React Loadable. Load splitted chunks was never that easy.

See https://github.com/themgoncalves/react-loadable-ssr-addon

like image 195
Marcos Gonçalves Avatar answered Jan 03 '23 15:01

Marcos Gonçalves