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'));
useEffect
, have you tried to avoid doing that? – Rowleyhydrate
which is a callback function that is called after hydration is complete. This callback function is where you should be removing no longer needed styles / variables from the DOM. With your current set up your application has yet to hydrate fully before you remove the server side styles, this means not all the styles for the elements have been created and they will be displayed unstyled until hydration is complete and the styles have fully been created by the client side. – Lefkowitz