fahad shaikh
fahad shaikh

Reputation: 641

Material UI style Disappeare on Page Refresh

I am converting my React app into Next app to take advantage of SSR. I am using Material ui 4 for styling.

I have implemented _app.js and _document.js file as per the Material ui documentation but the problem is when the page is loaded for the first time, material ui styles are not being applied but when I make some changes in my components then only all the styles appear.

I am posting this question only after referring this, this answers and other resources on internet

_app.js

import '@assets/fonts/global.css';
import React, {useState, useEffect} from "react";
import Layout from "@layout/Layout";
import Footer from "@layout/Footer/Footer";
import Header from "@layout/Header/Header";
//import Sidebar from "@layout/Sidebar/Sidebar";

//Material UI
import CssBaseline from "@material-ui/core/CssBaseline";
import theme from "@helper/theme/theme";
import {ThemeProvider as MuiThemeProvider} from "@material-ui/styles";

//Redux
import {wrapper} from "@store/store";


function MyApp({Component, pageProps}) {

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

    return (

        <>
            <MuiThemeProvider theme={theme}>
                <CssBaseline/>
                <Header/>
                <Layout>
                    <Component {...pageProps} />
                </Layout>
                <Footer/>
            </MuiThemeProvider>
        </>
    );
}

export default wrapper.withRedux(MyApp);

_document.js

import React from 'react';
import Document, {Html, Head, Main, NextScript} from 'next/document';
import {ServerStyleSheets} from '@material-ui/core/styles';
import theme from "@helper/theme/theme";

export default class MyDocument extends Document {

    render() {

        return (
            <Html lang="en">
                <Head>
                    <meta name="theme-color" content={theme.palette.primary.main} />
                </Head>
                <body>
                    <Main/>
                    <NextScript/>
                </body>
            </Html>
        );
    }
}

MyDocument.getInitialProps = async (ctx) => {

    console.log('DOC Called');

    // Render app and page and get the context of the page with collected side effects.
    const sheets = new ServerStyleSheets();
    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()],
    };
};

Note: Even after using _app.js and _document.js file as per the Material ui documentation I'm still getting the following warning in console

next-dev.js?3515:25 Warning: Prop `className` did not match.

Upvotes: 3

Views: 3658

Answers (2)

user19963522
user19963522

Reputation:

I had the same issue for days here are the things i did:

  • Made sure my theme is on src folder
  • I used this folder structure and _document.js and _app.js and index.js provided in material official example. Make sure to follow every detail provided in each of these files. they way things are imported, their folder structure, combination of theme and …
  • I turned off SSR for components such as footer or some other static data that didn't need SSR by adding nossr wrapper. I had breakpoints in my themes which caused to break css in refresh so turning off SSR when not needed made components to fully load on client:
import React from 'react';

import dynamic from 'next/dynamic';

const NoSSRWrapper = props => <React.Fragment>{props.children}</React.Fragment>;
export default dynamic(() => Promise.resolve(NoSSRWrapper), {
  ssr: false,
});
import NoSSRWrapper from '../../components/NoSSRWrapper';
function func() {
  return (
    <NoSSRWrapper>
//your component
   </NoSSRWrapper>
    )
}

Also I suggest instead of wrapping your _app.js with redux you use <Provider store={store}> something like this(small details of your _app.js matters)

import store from '../utils/store';
  return (
  <Provider store={store}>
        <ThemeProvider theme={theme}>
          <Layout>
            <Component {...pageProps} />
          </Layout>
        </ThemeProvider>
      </Provider>
)

Upvotes: 1

Haresh Samnani
Haresh Samnani

Reputation: 812

Perhaps the style mismatch issue? The reactStrictMode is turned on by default if using create-next-app

According to the following link here: https://github.com/mui/material-ui/issues/18018 Material UI v4 is not strict mode compatible so until then you can try disabling reactStrictMode or use Material UI v5.

// in next.config.js
module.exports = {
  reactStrictMode: false
}

Apologies if I misunderstood anything!

Upvotes: 0

Related Questions