Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Material UI: Styles flicker in and disappear

Styles appear for maybe 50ms and disappear in the below code in this SSR app. I'm curious what could be causing that.

// This component is a child of index.tsx in the /pages folder
    <Button
      color="primary"
      variant="outlined"
      size="large"
    >Test Button</Button>

After the styles disappear a plain HTML button is left.

I believe Next.js is causing this. I checked the Next.js file and have added the next/babel loader to .babelrc. Other than that I only saw this other relevant change. This is in /pages/_document.js:


MyDocument.getInitialProps = async ctx => {
  const sheets = new MuiServerStyleSheets();
  const originalRenderPage = ctx.renderPage;

  ctx.renderPage = () =>
    originalRenderPage({
      enhanceApp: App => props => sheets.collect(<App {...props} />),
    });

  const initialProps = await Document.getInitialProps(ctx);

  return {
    ...initialProps,
    // Styles fragment is rendered after the app and page rendering finish.
    styles: [...React.Children.toArray(initialProps.styles), sheets.getStyleElement()],
  };
};

Things done to attempt to resolve

  1. Restart server

No change to issue.

  1. Force refresh Chrome 78 (CTRL + F5)

No change.

Theory

I think there is a server side problem. Client and server should be on the same machine, localhost. That would explain the correct initial result (client initial UI) then being overridden by a server update.

Update 1

Forgot to mention that I did update /pages/_app.js too. Here's the updated portion:

class MyApp extends App {
  componentDidMount() {
    // Remove the server-side injected CSS.
    const jssStyles = document.querySelector('#jss-server-side');
    if (jssStyles && "parentElement" in jssStyles) {
      (jssStyles.parentElement as HTMLElement).removeChild(jssStyles);
    }
  }
like image 333
Sean D Avatar asked Nov 10 '19 18:11

Sean D


2 Answers

The root cause of this error for me, was that the classes generated during server side rendering of the document, don't match the styles that are generated after hydration.

One way to fix this, is to force a rerender after hidration.

One way to do this, is to update the key prop on your component.

// inside your component
const [key, setKey] = React.useState(0);

React.useEffect(() => {
  setKey(1);
}, []);

return (<MyComponent key={}key />)

My full _app.tsx file:

import React from 'react';
import {
  ThemeProvider,
  createGenerateClassName,
  StylesProvider
} from '@material-ui/core/styles';
import CssBaseline from '@material-ui/core/CssBaseline';

import { darkTheme } from '../theme';

const generateClassName = createGenerateClassName({
  productionPrefix: 'myclasses-'
});

export default function MyApp(props) {
  const { Component, pageProps } = props;

  const [key, setKey] = React.useState(0);

  React.useEffect(() => {
    setKey(1);
  }, []);

  React.useEffect(() => {
    const jssStyles = document.querySelector('#jss-server-side');
    if (jssStyles) {
      jssStyles.parentElement.removeChild(jssStyles);
    }
  }, []);

  return (
    <StylesProvider key={key} generateClassName={generateClassName}>
      <React.Fragment>
        <ThemeProvider theme={darkTheme}>
          <CssBaseline />
          <Component {...pageProps} />
        </ThemeProvider>
      </React.Fragment>
    </StylesProvider>
  );
}
like image 126
R R Avatar answered Oct 31 '22 13:10

R R


TLDR; Make sure to set NODE_ENV to production if you are running a production build, eg: NODE_ENV=production npm start


For me, this was happening only on my machine when creating a production build with npm run build and then running it with npm start.

It was strange why server-rendered responses used development style classes such as makeStyles-root-123 instead of jss123 as explained by https://material-ui.com/styles/advanced/#class-names.

Clearly, some part of the server acted as we were still in a development environment. To fix this I tried starting the production build with NODE_ENV set to "production" and the issue was gone.

like image 36
Denis Pshenov Avatar answered Oct 31 '22 15:10

Denis Pshenov