Material-ui: Server side rendering with Express - warning on the client checksum & Styling

Created on 10 Jun 2016  路  7Comments  路  Source: mui-org/material-ui

Problem description

I could see the below warning even after passing the userAgent while rendering on the server side. Please assist me on this , if I am doing anything wrong. On the client side React is trying to reuse markup(component) , since checksum is invalid so it is throwing the warning. I could see the issue is due to Isomorphic styling and node is not able to compile the CSS (I may be wrong).

Code
https://github.com/sabha/React-Redux-Router-MaterialUI-ServerSideRendering

Server Side Rendering

global.navigator = {
          userAgent: req.headers['user-agent']
        };
      const muiTheme = getMuiTheme({userAgent: req.headers['user-agent']});  
      // hey we made it!
      const appHtml = renderToString(
        <MuiThemeProvider muiTheme={muiTheme}>
          <Provider store={store}>
              <RouterContext {...props}/>
          </Provider>
        </MuiThemeProvider>
          )

Client Side Render

import getMuiTheme from 'material-ui/styles/getMuiTheme';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';

render(  
    <MuiThemeProvider muiTheme={getMuiTheme()}>
        <Provider store={store}>
            <Router routes={LoginRoutes} history={browserHistory}/>
        </Provider>
    </MuiThemeProvider>,
  document.getElementById('app')
)

MUI Component

'warning.js:44Warning: 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) 0;text-align:center;mui-prepared:;-webki
(server) 0;text-align:center;-webkit-user-select:'

question

Most helpful comment

Solved the issue but setting process.env for the client side.

 plugins: [
        new webpack.DefinePlugin({
            'process.env': {
                'NODE_ENV': JSON.stringify(process.env.NODE_ENV)
            }
        }),
    ]

All 7 comments

Is it good practice to go with this warning and fix it later or I should build the app with client side rendering and later make the server side rendering . .

I've met this problem before and dealt with it for a long period. I don't use react-router so I've no idea this would help you. The solution is simple, just passing navigator.userAgent value to your custom theme in client side AGAIN, it's like:

 <MuiThemeProvider muiTheme={getMuiTheme({userAgent: navigator.userAgent)}>
   <Provider store={store}>
     ... 
   </Provider>
</MuiThemeProvider>

@OshotOkill Still the same warning.

I had this problem, I was able to get around it by monkeypatching the prepareStyles method to ignore muiPrepared when passing style props onto react.

var theme = getMuiTheme({}, { userAgent: ... });
var original = theme.prepareStyles;
theme.prepareStyles = function(style) {
    var out = style.muiPrepared ? style : original(style);
    if (out && out.muiPrepared) {
        delete out.muiPrepared;
    }
    return out;
};

Hope that helps!

@OshotOkill So how do you get the code working isomorphically?
It can be request.headers['user-agent'] on the server side and navigator.userAgent on the client side, but the global navigator variable should not be set on the server side.

Well, for those who are googling for this issue: I managed to sort out the navigator issue by storing navigator (taken from request.headers['user-agent']) inside Redux store (and putting it there on the server side, therefore client-side navigator.userAgent is not used at all).

@connect(model => ({ navigator: model.navigator }))
export default class Form extends Component
{
    getChildContext()
    {
        return {
            muiTheme: getMuiTheme({ userAgent: this.props.navigator.userAgent })
        }
    }
}

// `navigator` reducer must also be created otherwise `navigator` will be `undefined`

It fixed the autoprefixer "React attempted to reuse markup" warning, but here's the new one:

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) aitDialog-undefined-8741" style="-webkit
(server) aitDialog-undefined-3418" style="-webkit
Server-side React render was discarded. Make sure that your initial render does not contain any client-side code.

The cause of the error is this weird autogenerated id:
id="undefined-PortraitDialog-undefined-8741"
Which has, apart from the weird undefined parts, that randomly generated number in the end, which is different every time a render happens therefore discarding previously rendered React markup.

This issue is unresolved and is described in https://github.com/callemall/material-ui/issues/3757
Specifying a manually set id on a <DatePicker/> seems to have worked around this issue.

Solved the issue but setting process.env for the client side.

 plugins: [
        new webpack.DefinePlugin({
            'process.env': {
                'NODE_ENV': JSON.stringify(process.env.NODE_ENV)
            }
        }),
    ]
Was this page helpful?
0 / 5 - 0 ratings

Related issues

activatedgeek picture activatedgeek  路  3Comments

ericraffin picture ericraffin  路  3Comments

finaiized picture finaiized  路  3Comments

ryanflorence picture ryanflorence  路  3Comments

pola88 picture pola88  路  3Comments