samedi 14 février 2015

What is the best way to selectively server-render in an isomorphic React web app?


I want the best performance for a web page with a lot of content. Of particular interest, on a mobile device, I would like users to see content above the fold as quickly as possible, and then for the application to bootstrap as quickly as possible.


I have a variable isBrowser which is true in the browser environment but false in the server environment. Consider the following render function:



render() {
return (
<div>
<ContentAboveTheFold />
{ isBrowser && <ContentBelowTheFold /> }
</div>
)
}


Note that by structuring the render() this way, the server has less markup to render, less data is transferred over the wire, and the browser has less markup to render during it's first pass.


This works fine, but in the console React warns



React attempted to use reuse markup in a container but the checksum was invalid. This generally means that you are using server rendering and the markup generated on the server was not what the client was expecting. React injected new markup to compensate which works but you have lost many of the benefits of server rendering. Instead, figure out why the markup being generated is different on the client or server.



On the server, React renders the markup with a checksum embedded as an attribute in the top-level element (for ex data-react-checksum="941190765"). Then on the client, react calculates a checksum after the first render and if it differs from the server's checksum, it throws away the server-generated markup entirely and replaces it with the client-generated markup.


As a workaround, I found that in my top-level component's componentDidMount lifecycle method I could schedule the following operation on the next animation frame:



componentDidMount() {
requestAnimationFrame(() => {
appIsMounted = true;
this.forceUpdate();
});
}


Then I could write my render method like this and react did not generate any warnings about the checksum:



render() {
return (
<div>
<ContentAboveTheFold />
{ appIsMounted && <ContentBelowTheFold /> }
</div>
)
}


Is there any appreciable performance advantage to doing it this way? In either case, the content above the fold will appear just as quickly, right? Is the additional complexity justified?





Aucun commentaire:

Enregistrer un commentaire