Next JS not properly loading Material UI styles until refresh

Viewed 2796

EDIT: Reproducible bug https://github.com/ganavol409/next-material-ui-classes-bug

Seems to occur with with HoC components and both importing useStyles from Material UI


What has been implemented:

https://github.com/mui-org/material-ui/blob/master/examples/nextjs/pages/_document.js + next js project with material ui and material styles

Current behaviour:

Page css (specifically 'classes' field in Material UI) doesn't load upon coming from Next JS Link/Next JS Router module. After the refresh 'classes' field loads

Expected behaviour:

All of css loading if user comes from Next JS Link/Next JS Router module or types in website address manually (currently only works if user manually writes it or refreshes the website/page)

Code:

<Container maxWidth="sm" disableGutters classes={{ maxWidthSm: classes.smContainerWidth }}>
...
</Container>

smContainerWidth: {
    maxWidth: '750px'
},

 useEffect(() => {
    router.push('/');
 }, []);

The container will load default 600px width if user comes from Next JS Link/Next JS Router instead of 750px and after user refreshes container will be 750px width

automatic router push

2 Answers

I have reproduced your example but I don't have that behavior. The 750px max-width is working when you reload the page, but also when you click on a next Link to go to that page.

Here is the code (the style is on about page), and here is a live version.

Edit:

I think your problem doesn't come from HoC, but simply from importing a file where makeStyles is already called in 2 different pages.

To solve it you can either export a function that, when called, will call makeStyles:

// in styles.js
const useStylesCreator = () => {
  return makeStyles((theme) => {
    return {
      hoverElevationCapitalizeButton: {
        padding: "9px 23.1px",
        textTransform: "none",

        "&:hover": {
          boxShadow:
            "0px 3px 1px -2px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 1px 5px 0px rgba(0,0,0,0.12)",
        },
      },
    };
  });
};
export default useStylesCreator;

// in your components
const Login = HoCA(() => {
  const classes = useStylesCreator()();
  ...

Or, probably more elegant, you can export an object holding the styles, and call makeStyles only after importing in the component file:

// in styles.js
const styles = {
  hoverElevationCapitalizeButton: {
    padding: "9px 23.1px",
    textTransform: "none",

    "&:hover": {
      boxShadow:
        "0px 3px 1px -2px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 1px 5px 0px rgba(0,0,0,0.12)",
    },
  },
};
export default styles;

// in your components
const useStyles = makeStyles((theme) => styles);

const Login = HoCA(() => {
  const classes = useStyles();
  ...

I had the same problem after some update, the second option mentioned by Roman Mkrtchian worked for me, to have the makeStyles in the same file as your component

// in your components
const useStyles = makeStyles((theme) => styles);

const Login = HoCA(() => {
  const classes = useStyles();
  ...
Related