I have integrated material UI in my Server side rendering app and have followed the code given here. Material UI css is been added to the html on the server side itself.
However, on the initial load, material ui styles are not applied which is causing it to flicker.
I tried using <cssbaseline>
along with the below code but did not see any difference.
Here is my code: server.js
import App from '../common/containers/App';
import { Provider } from 'react-redux';
import React from 'react';
import configureStore from '../common/store/configureStore';
import express from 'express';
import qs from 'qs';
import { renderToString } from 'react-dom/server';
import serialize from 'serialize-javascript';
import { StaticRouter, matchPath } from 'react-router-dom';
import {theme} from '../theme';
import { ServerStyleSheets, ThemeProvider } from '@material-ui/styles';
import routes from './routes'
import "../common/assets/SCSS/app.scss";
const assets = require(process.env.RAZZLE_ASSETS_MANIFEST);
const server = express();
server
.disable('x-powered-by')
.use(express.static(process.env.RAZZLE_PUBLIC_DIR))
.get('/*', (req, res) => {
const activeRoute = routes.find((route) => matchPath(req.url, route)) || {}
const promise = activeRoute.fetchInitialData
? activeRoute.fetchInitialData(req.path)
: Promise.resolve()
promise.then((apiResult) => {
const sheets = new ServerStyleSheets();
const counter = apiResult || 0;
const preloadedState = { counter };
const store = configureStore(preloadedState);
const context = {};
const markup = renderToString(
sheets.collect(
<Provider store={store}>
<ThemeProvider theme={theme}>
<StaticRouter location={req.url} context={context}>
<App />
</StaticRouter>
</ThemeProvider>
</Provider>
));
const css = sheets.toString();
const finalState = store.getState();
const html = `<!doctype html>
<html lang="">
<head>
${assets.client.css
? `<link rel="stylesheet" href="${assets.client.css}">`
: ''}
${css ? `<style id='jss-ssr'>${css}</style>` : ''}
${process.env.NODE_ENV === 'production'
? `<script src="${assets.client.js}" defer></script>`
: `<script src="${assets.client.js}" defer crossorigin></script>`}
</head>
<body>
<div id="root">${markup}</div>
<script>
window.__PRELOADED_STATE__ = ${serialize(finalState)}
</script>
</body>
</html>`
res.send(html);
});
});
export default server;
Client.js
import React,{useEffect} from 'react';
import { hydrate } from 'react-dom';
import {theme} from '../theme';
import { ThemeProvider } from '@material-ui/styles';
import { Provider } from 'react-redux';
import configureStore from '../common/store/configureStore';
import App from '../common/containers/App';
import { BrowserRouter } from "react-router-dom";
import "../common/assets/SCSS/app.scss";
import * as serviceWorker from '../serviceWorker';
import CssBaseline from '@material-ui/core/CssBaseline';
const store = configureStore(window.__PRELOADED_STATE__);
const Client = () => {
useEffect(() => {
const jssStyles = document.querySelector('#jss-ssr');
if (jssStyles) {
jssStyles.parentElement.removeChild(jssStyles);
}
}, []);
return(
<Provider store={store}>
<ThemeProvider theme={theme}>
<CssBaseline />
<BrowserRouter>
<App />
</BrowserRouter>
</ThemeProvider>
</Provider>
);
}
hydrate(<Client />,document.getElementById('root'));
This is caused by your client side code removing the server generated styling before the client styling has been generated.
The hydrate function provided by react-dom
has a 3rd parameter which is a callback function that is called after hydration of the app is complete.
This callback function should be used to ensure that the app has completed hydration and has generated the client styling.
import React,{useEffect} from 'react';
import { hydrate } from 'react-dom';
import {theme} from '../theme';
import { ThemeProvider } from '@material-ui/styles';
import { Provider } from 'react-redux';
import configureStore from '../common/store/configureStore';
import App from '../common/containers/App';
import { BrowserRouter } from "react-router-dom";
import "../common/assets/SCSS/app.scss";
import * as serviceWorker from '../serviceWorker';
import CssBaseline from '@material-ui/core/CssBaseline';
const store = configureStore(window.__PRELOADED_STATE__);
const Client = () => {
return(
<Provider store={store}>
<ThemeProvider theme={theme}>
<CssBaseline />
<BrowserRouter>
<App />
</BrowserRouter>
</ThemeProvider>
</Provider>
);
}
hydrate(
<Client />,
document.getElementById('root'),
() => {
const jssStyles = document.querySelector('#jss-ssr');
if (jssStyles) {
jssStyles.parentElement.removeChild(jssStyles);
}
}
);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With