Text content did not match. Warning in React 16

26,336

Solution 1

For those discovering this error because your client and server purposefully render different content (like the server rendering a dark theme which gets replaced with the user preference on load), use suppressHydrationWarning to suppress the error.

For example:

<div suppressHydrationWarning>Ignore this</div>

Solution 2

The problem here is that your server-side application does not reflect code changes. To do that you have to configure your express app as a webpack entry.

Briefly, you need 2 webpack configurations one for server and another for client code. The server one will look something like this

module.exports = {
  entry: {
    server: './server.js',
  },
  output: {
    path: path.join(__dirname, 'dist'),
    publicPath: '/',
    filename: '[name].js'
  },
  target: 'node',
  node: {
    // Need this when working with express, otherwise the build fails
    __dirname: false,   // if you don't put this is, __dirname
    __filename: false,  // and __filename return blank or /
  },
  externals: [nodeExternals()], // Need this to avoid error when working with Express
  module: {
    rules: [
      {
        // Transpiles ES6-8 into ES5
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      },
      {
        // Loads the javacript into html template provided.
        // Entry point is set below in HtmlWebPackPlugin in Plugins 
        test: /\.html$/,
        use: [{loader: "html-loader"}]
      }
    ]
  },
  plugins: [
    new HtmlWebPackPlugin({
      template: "./index.html",
      filename: "./index.html",
      excludeChunks: [ 'server' ]
    })
  ]
}

Here is a nice article explaining how to do that in details

Share:
26,336
Pavel Perevezencev
Author by

Pavel Perevezencev

Updated on April 30, 2021

Comments

  • Pavel Perevezencev
    Pavel Perevezencev about 3 years

    I trying to build ReactJs application with server side rendering My entry points for client and server:

    client.jsx

    const store = createStore(window.__INITIAL_STATE__);
    
    hydrate(
      <Provider store={store}>
        <BrowserRouter>{renderRoutes(routes)}</BrowserRouter>
      </Provider>,
      document.querySelector('#root')
    );
    

    server.jsx

    const app = express();
    
    if (isDev) {
      const webpack = require('webpack');
      const webpackDevMiddleware = require('webpack-dev-middleware');
      const config = require('../../webpack.config.js');
      const compiler = webpack(config);
    
      app.use(express.static('/public'));
      app.use(
        webpackDevMiddleware(compiler, {
          publicPath: config.output.publicPath,
          stats: 'errors-only',
        })
      );
    }
    
    app.get('*', (req, res) => {
      const helmet = Helmet.renderStatic();
      const htmlAttrs = helmet.htmlAttributes.toComponent();
      const bodyAttrs = helmet.bodyAttributes.toComponent();
    
      const context = {};
      const data = {};
    
      res.set('content-type', 'text/html');
    
      res.send(
        '<!DOCTYPE html>' +
          renderToString(
            <html {...htmlAttrs}>
              <head>
                {helmet.title.toComponent()}
                {helmet.meta.toComponent()}
                {helmet.link.toComponent()}
              </head>
              <body {...bodyAttrs}>
                <div id="root">
                  <StaticRouter location={req.url} context={context}>
                    {renderRoutes(routes)}
                  </StaticRouter>
                </div>
                <script
                  dangerouslySetInnerHTML={{
                    __html: `window.__INITIAL_STATE__ = ${JSON.stringify(data)}`,
                  }}
                />
                <script src="/public/vendor.js" />
                <script src="/public/app.js" />
              </body>
            </html>
          )
      );
    });
    

    And component:

    home.jsx

    import React, { Component } from 'react';
    
    class Home extends Component {
      render() {
        return <div>home</div>;
      }
    }
    
    export default Home;
    

    When I change in my component Home and refresh browser page I get this error:

    Warning: Text content did not match. Server: "home" Client: "home1"

    Its ok because server render old version of my code. How to reload the code on the server so that the client and server versions are equal?

  • locopump
    locopump almost 3 years
    thanks this help me, it was very simple =D, Thanks :D