Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Warning: React attempted to reuse markup in a container but the checksum was invalid

I'm trying to get an isomorphic Node.js, Express, Webpack, React app working. I'm getting the following error. Any suggestions on how to fix it?

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:  (client) rgin:0;display:flex;-webkit-align-items:  (server) rgin:0;display:flex;align-items:center;j  warning @   warning.js:45 ReactMount._mountImageIntoNode  @   ReactMount.js:807 wrapper @   ReactPerf.js:66 mountComponentIntoNode  @   ReactMount.js:268 Mixin.perform   @   Transaction.js:136 batchedMountComponentIntoNode   @   ReactMount.js:282 Mixin.perform   @   Transaction.js:136 ReactDefaultBatchingStrategy.batchedUpdates @   ReactDefaultBatchingStrategy.js:62 batchedUpdates  @   ReactUpdates.js:94 ReactMount._renderNewRootComponent  @   ReactMount.js:476 wrapper @   ReactPerf.js:66 ReactMount._renderSubtreeIntoContainer  @   ReactMount.js:550 ReactMount.render   @   ReactMount.js:570 wrapper @   ReactPerf.js:66 (anonymous function)    @   client.jsx:14 (anonymous function)    @   iso.js:120 each    @   iso.js:21 bootstrap   @   iso.js:111 (anonymous function)    @   client.jsx:12 __webpack_require__ @   bootstrap d56606d95d659f2e05dc:19 (anonymous function)    @   bootstrap d56606d95d659f2e05dc:39 (anonymous function)    @   bootstrap d56606d95d659f2e05dc:39 

This is what is being delivered by the server to the browser initially:

<!doctype html> <html lang="">      <head>         <title>my title</title>          <meta name="apple-mobile-web-app-title" content="my title" data-react-helmet="true" /> <meta name="apple-mobile-web-app-status-bar-style" content="black" data-react-helmet="true" /> <meta name="apple-mobile-web-app-capable" content="yes" data-react-helmet="true" /> <meta name="mobile-web-app-capable" content="yes" data-react-helmet="true" /> <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" data-react-helmet="true" /> <meta name="description" content="my description." data-react-helmet="true" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" data-react-helmet="true" /> <meta charset="utf-8" data-react-helmet="true" />          <link rel="stylesheet" href="/assets/styles/reset.css" data-react-helmet="true" /> <link rel="stylesheet" href="/assets/styles/base.css" data-react-helmet="true" /> <link rel="stylesheet" href="/assets/styles/Carousel.css" data-react-helmet="true" /> <link rel="stylesheet" href="/assets/styles/main.css" data-react-helmet="true" /> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto+Condensed" type="text/css" data-react-helmet="true" /> <link rel="icon" href="/assets/185bb6f691241307862b331970a6bff1.ico" type="image/x-icon" data-react-helmet="true" />          SCRIPT      </head>     <body>         <script src="https://cdn.firebase.com/js/client/2.2.7/firebase.js"></script>         <script src="https://cdn.firebase.com/libs/reactfire/0.4.0/reactfire.min.js"></script>          <div class="app"> <div class="___iso-html___" data-key="_0"><div data-reactid=".1hkqsbm9n9c" data-react-checksum="794698749"><div data-reactid=".1hkqsbm9n9c.0"><div data-reactid=".1hkqsbm9n9c.0.$=10"></div><div style="position:fixed;z-index:2;top:0;left:0;right:0;height:60px;color:rgb(219,219,219);font-family:mainnextcondensed_ultralight;font-size:17px;overflow:hidden;" data-reactid=".1hkqsbm9n9c.0.$/=11"><div style="position:absolute;left:0;top:0;background-color:rgba(27,27,27,0.92);padding-right:35px;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=10"><div style="float:left;height:60px;width:13px;border-left:5px solid rgb(210,45,164);" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=10.$/=10"></div><div style="float:left;height:60px;width:227px;background-image:url(data:image/png;base64,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);background-repeat:no-repeat;background-position:center;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=10.$/=11"></div><div style="display:none;width:0;height:0;border-style:solid;border-width:6px 6px 0 6px;border-color:rgb(117,117,117) transparent transparent transparent;-webkit-transform:rotate(360deg);float:left;margin-left:6px;margin-top:26px;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=10.$/=12"></div></div><div style="position:absolute;top:0px;left:280px;width:340px;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=11"><div style="background-color:rgba(27,27,27,0.92);height:10px;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=11.$/=10"></div><div style="background-color:rgba(53,53,53,0.84);height:40px;position:relative;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=11.$/=11"><div style="position:absolute;top:0;bottom:0;left:0;right:0;padding:0;margin:0;display:flex;align-items:center;justify-content:center;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=11.$/=11.$=10"><div style="background-image:url(&#x27;/assets/3bec3e57cb5ee05658440d21984fb7b7.png&#x27;);background-repeat:no-repeat;background-position:-58px -194px;width:23px;height:22px;position:absolute;top:50%;left:10px;margin-top:-11px;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=11.$/=11.$=10.$icon"></div></div><div style="position:absolute;left:40px;right:40px;top:0px;bottom:0px;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=11.$/=11.$/=12"><input type="text" style="width:100%;height:100%;font-size:14px;font-family:mainnext_regular;background-color:transparent;color:#ffffff;" placeholder="SEARCH ARTISTS, TRACKS, ALBUMS" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=11.$/=11.$/=12.0"/></div></div><div style="background-color:rgba(27,27,27,0.92);height:10px;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=11.$/=12"></div></div><div style="position:absolute;top:0px;left:620px;right:0px;background-color:rgba(27,27,27,0.92);height:60px;line-height:60px;overflow:hidden;min-width:500px;padding-left:10px;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=12"><div style="position:absolute;top:0px;bottom:0px;right:0px;width:357px;padding-left:141px;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=12.0"><a class="" href="/import" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=12.0.$/=10"><div style="padding-left:40px;position:absolute;left:0px;top:10px;bottom:10px;cursor:pointer;line-height:40px;color:rgb(255,255,255);" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=12.0.$/=10.$import"><div style="position:absolute;top:0;bottom:0;left:0;right:0;padding:0;margin:0;display:flex;align-items:center;justify-content:center;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=12.0.$/=10.$import.$=10"><div style="background-image:url(&#x27;/assets/3bec3e57cb5ee05658440d21984fb7b7.png&#x27;);background-repeat:no-repeat;background-position:0px -194px;width:28px;height:28px;position:absolute;top:50%;left:0px;margin-top:-14px;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=12.0.$/=10.$import.$=10.$icon"></div></div><span data-reactid=".1hkqsbm9n9c.0.$/=11.$/=12.0.$/=10.$import.1">Import Playlists</span></div></a><div style="margin-left:10px;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=12.0.$admin/=1$admin"><div style="cursor:pointer;float:left;" data-reactid=".1hkqsbm9n9c.0.$/=11.$/=12.0.$admin/=1$admin.$login">Login</div></div></div></div></div></div><noscript data-reactid=".1hkqsbm9n9c.1"></noscript></div></div> <div class="___iso-state___" data-key="_0" data-meta="{}" data-state="&quot;{\&quot;UserStore\&quot;:{\&quot;user\&quot;:{\&quot;authenticated\&quot;:false,\&quot;isWaiting\&quot;:false}},\&quot;SearchStore\&quot;:{\&quot;focused\&quot;:false,\&quot;input\&quot;:\&quot;\&quot;,\&quot;timeout\&quot;:null,\&quot;searchRequests\&quot;:[],\&quot;artists\&quot;:null,\&quot;artistsFailed\&quot;:false,\&quot;artistsLoading\&quot;:false,\&quot;tracks\&quot;:null,\&quot;tracksFailed\&quot;:false,\&quot;tracksLoading\&quot;:false,\&quot;albums\&quot;:null,\&quot;albumsFailed\&quot;:false,\&quot;albumsLoading\&quot;:false,\&quot;playlists\&quot;:null,\&quot;playlistsFailed\&quot;:false,\&quot;playlistsLoading\&quot;:false,\&quot;youtubes\&quot;:null,\&quot;youtubesFailed\&quot;:false,\&quot;youtubesLoading\&quot;:false,\&quot;soundclouds\&quot;:null,\&quot;soundcloudsFailed\&quot;:false,\&quot;soundcloudsLoading\&quot;:false},\&quot;PlayerStore\&quot;:{\&quot;player\&quot;:null,\&quot;playerSecond\&quot;:null,\&quot;playingTrack\&quot;:null,\&quot;playingTrackSecond\&quot;:null,\&quot;videoId\&quot;:null,\&quot;videoIdSecond\&quot;:null,\&quot;makingPlayingTrackPlayable\&quot;:false,\&quot;radio\&quot;:false,\&quot;startSeconds\&quot;:0,\&quot;current\&quot;:0,\&quot;total\&quot;:0,\&quot;perc\&quot;:0,\&quot;currentSecond\&quot;:0,\&quot;totalSecond\&quot;:0,\&quot;percSecond\&quot;:0,\&quot;playing\&quot;:false,\&quot;playingSecond\&quot;:false,\&quot;secondsListened\&quot;:0,\&quot;secondsListenedSecond\&quot;:0,\&quot;expand\&quot;:false,\&quot;source\&quot;:null,\&quot;tracksQueue\&quot;:[],\&quot;tracksPrevQueue\&quot;:[],\&quot;favorite\&quot;:false,\&quot;random\&quot;:false,\&quot;repeat\&quot;:false,\&quot;mute\&quot;:false,\&quot;volume\&quot;:100,\&quot;mode\&quot;:\&quot;standard\&quot;},\&quot;ImportStore\&quot;:{\&quot;url\&quot;:\&quot;\&quot;,\&quot;error\&quot;:false,\&quot;focused\&quot;:false,\&quot;loading\&quot;:false,\&quot;loaded\&quot;:false,\&quot;playlist\&quot;:null}}&quot;"></div> </div>          <!-- Google Analytics: change UA-XXXXX-X to be your site's ID -->         <!--         <script>             (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){                 (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),                     m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)             })(window,document,'script','//www.google-analytics.com/analytics.js','ga');             ga('create', 'UA-XXXXX-X', 'auto');             ga('send', 'pageview');         </script>         -->         <script src="https://cdnjs.cloudflare.com/ajax/libs/fastclick/1.0.3/fastclick.min.js"></script>         <script type="text/javascript">           if ('addEventListener' in document) {             document.addEventListener('DOMContentLoaded', function() {                 FastClick.attach(document.body);             }, false);           }         </script>         <script type="text/javascript" charset="utf-8" src="/assets/app.js"></script>     </body> </html> 

This is my server.jsx:

import Iso from 'iso'; import React from 'react'; import ReactDomServer from 'react-dom/server'; import { RoutingContext, match } from 'react-router' import createLocation from 'history/lib/createLocation';  import alt from 'altInstance'; import routes from 'routes.jsx'; import html from 'base.html';  /*  * @param {AltObject} an instance of the Alt object  * @param {ReactObject} routes specified in react-router  * @param {Object} Data to bootstrap our altStores with  * @param {Object} req passed from Express/Koa server  */ const renderToMarkup = (alt, state, req, res) => {   let markup, content;   let location = new createLocation(req.url);   alt.bootstrap(state);    match({ routes, location }, (error, redirectLocation, renderProps) => {     if (redirectLocation)       res.redirect(301, redirectLocation.pathname + redirectLocation.search)     else if (error)       res.status(500).send(error.message)     else if (renderProps == null)       res.status(404).send('Not found')     else       content = ReactDomServer.renderToString(<RoutingContext {...renderProps} />);       markup = Iso.render(content, alt.flush());   });    return markup; };  /*   * Export render function to be used in server/config/routes.js  * We grab the state passed in from the server and the req object from Express/Koa  * and pass it into the Router.run function.  */ export default function render(state, req, res) {   const markup = renderToMarkup(alt, state, req, res);   return html.replace('CONTENT', markup); }; 

And this is my client.jsx:

import React from 'react'; import ReactDOM from 'react-dom'; import Iso from 'iso'; import createBrowserHistory from 'history/lib/createBrowserHistory'; import { Router } from 'react-router'; import alt from 'altInstance'; import routes from 'routes.jsx';  /*  * Client side bootstrap with iso and alt  */ Iso.bootstrap((state, _, container) => {   alt.bootstrap(state);   ReactDOM.render(<Router history={createBrowserHistory()} children={routes} />, container); }); 

And my routes.jsx:

import React from 'react'; import Route from 'react-router'; import App from 'components/App'; import ImportPlaylist from 'components/ImportPlaylist'; import Login from 'components/Login'; import Logout from 'components/Logout'; import Player from 'components/Player/Player'; import Test from 'components/Test';  export default (   <Route path="/" component={App}>     <Route path="login" component={Login} />     <Route path="logout" component={Logout} />     <Route name="test" path="test" component={Test} />             <Route name="import" path="import" component={ImportPlaylist} />     <Route name="player" path="/:playlist" component={Player} />   </Route> ); 
like image 485
HelpMeStackOverflowMyOnlyHope Avatar asked Nov 04 '15 11:11

HelpMeStackOverflowMyOnlyHope


2 Answers

Note: This applies to older versions of React. If you're using React 16, you should use ReactDOM.hydrate()

Also, the below suggestion will result in a client-side re-render, as suggested by one of the answers below.


This may sound crazily simple, but in your server-side template, wrap your React markup in an extra <div>:

<!-- hypothetical handlebars template --> <section role="main" class="react-container"><div>{{{reactMarkup}}}</div></section> 

Why does this work? On the client, React has a propensity to wrap its rendering of your root component with a superfluous div. ReactDOMServer.render doesn't seem to behave in this manner, thus when one renders into the same container isomorphically, the Adler-32 checksum of your DOM differs.

like image 130
James Wright Avatar answered Oct 01 '22 11:10

James Wright


For those googling and coming here, one weird way of ending up with this issue is where you're not even using isomorphic rendering (i.e. not rendering anything on the server side). This happened with me when using a template with the HtmlWebpackPlugin to process an index.html file.

In my index.html file I already included the bundle.js file myself, and the above plugin also includes another bundle.js via a script-src. Make sure you're setting inject: false to your HtmlWebpackPlugin constructor.

like image 31
ragebiswas Avatar answered Oct 01 '22 11:10

ragebiswas