Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React SSR - handle window.height/width

I am using React with SSR FlowRouter.

Because of this lines:

var height = (Meteor.isClient ? window.innerHeight : 0);
<div style={{top: height+'px' }}>

I get such a warning:

Warning: React attempted to 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.

I know thats because of difference between client and server code (I don't have access to window on my server).

Is there any way to avoid this warning?

like image 965
Gemmi Avatar asked Oct 18 '22 06:10

Gemmi


1 Answers

The warning you are facing is because of a checksum error between the initially rendered html on the server and the client. As you correctly pointed out, this is because, you do not have the window object on the server and hence, cannot calculate window.innerHeight. This is causing the rendered html to differ in the style attribute of the div and causing the warning.

A possible workaround would be to move the height variable to the state of the component and set it to an initial state of 0. Then perform the check

this.setState({height: (Meteor.isClient ? window.innerHeight : 0)});

in componentWillMount and set the correct height here. This way the initial render of both client and server would be the same. But, since componentDidMount is only called on the client, it will re-render the component with the correct height from the window when the state is changed.

From the docs

If you intentionally need to render something different on the server and the client, you can do a two-pass rendering. Components that render something different on the client can read a state variable like this.state.isClient, which you can set to true in componentDidMount(). This way the initial render pass will render the same content as the server, avoiding mismatches, but an additional pass will happen synchronously right after hydration. Note that this approach will make your components slower because they have to render twice, so use it with caution.

like image 157
palsrealm Avatar answered Oct 21 '22 06:10

palsrealm