最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - MaterialUI makeStyles undoes custom css upon refresh in NextJS - Stack Overflow

programmeradmin2浏览0评论

I am working on a NextJS site that has some custom styling that is being applied via MaterialUI's makeStyles. It works fine on the first load and then undoes all of the custom work on the second. It seems that it has something to do with the route as the only time that it works is when I first am directed to the page itself. It is happening on 2 different pages one is being directed via href='/login'and the other is being directed via next/router router.push('/register')

I am assuming that this has to do with the way that Next loads the page? But I will say that both of these are prerendered pages according to the icon at the bottom right.

import React, {useState} from 'react';
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { login } from '../store/user/action'
import { useRouter } from 'next/router'

import TextField from '@material-ui/core/TextField';
import { makeStyles } from '@material-ui/core/styles';

const style = makeStyles({
    root: {
        marginBottom: '20px',
        textAlign: 'center'
    },
  });


function Signin({login}) {
    const [email, setEmail] = useState('');
    const [password, setPassword] = useState('');
    
    const router = useRouter();

    const clickRegister = (e) => {
        e.preventDefault();
        router.push('/register')
    }

    const classStyle = style();

    return (
        <div className='flex flex-column center m-20 w-750'>
            <h3 className='m-20'>Login</h3>
            <form className='flex flex-column w-750 center' onSubmit={e=>login(e, {email, password})} >
                <TextField
                    className={classStyle.root}
                    required
                    type='email'
                    id="email"
                    label="Email"
                    variant="outlined"
                    onChange={e=>setEmail(e.target.value)}
                />
                <TextField
                    className={classStyle.root}
                    required
                    type='password'
                    id="password"
                    label="Password"
                    variant="outlined"
                    onChange={e=>setPassword(e.target.value)}
                />
                
                <input 
                    type='submit'
                    className='purple-button mt-20 h-3' 
                    onClick={e=>login(e)}
                    value='Login' />
            </form>
            <p>Don't Have an account?</p>
            <form onSubmit='/register'>
                <input value='Register' type='submit' className='flex flex-column w-750 center purple-button h-3' onClick={e=>clickRegister(e)} />
            </form>

        </div>
    )
}



const mapStateToProps = (state) => ({
    email: state.user.email,
    token: state.user.token,
    isLoggedIn: state.user.isLoggedIn,
  })
  
const mapDispatchToProps = (dispatch) => {
    return {
        login: bindActionCreators(login, dispatch),
    }
}
  
export default connect(mapStateToProps, mapDispatchToProps)(Signin)
"dependencies": {
    "@material-ui/core": "4.11.3",
    "axios": "0.21.1",
    "material-ui": "0.20.2",
    "next": "9.4.1",
    "next-redux-wrapper": "^6.0.1",
    "react": "^16.12.0",
    "react-dom": "^16.12.0",
    "react-redux": "7.1.3",
    "redux": "4.0.5",
    "redux-devtools-extension": "2.13.8",
    "redux-thunk": "2.3.0"
  },

I am working on a NextJS site that has some custom styling that is being applied via MaterialUI's makeStyles. It works fine on the first load and then undoes all of the custom work on the second. It seems that it has something to do with the route as the only time that it works is when I first am directed to the page itself. It is happening on 2 different pages one is being directed via href='/login'and the other is being directed via next/router router.push('/register')

I am assuming that this has to do with the way that Next loads the page? But I will say that both of these are prerendered pages according to the icon at the bottom right.

import React, {useState} from 'react';
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { login } from '../store/user/action'
import { useRouter } from 'next/router'

import TextField from '@material-ui/core/TextField';
import { makeStyles } from '@material-ui/core/styles';

const style = makeStyles({
    root: {
        marginBottom: '20px',
        textAlign: 'center'
    },
  });


function Signin({login}) {
    const [email, setEmail] = useState('');
    const [password, setPassword] = useState('');
    
    const router = useRouter();

    const clickRegister = (e) => {
        e.preventDefault();
        router.push('/register')
    }

    const classStyle = style();

    return (
        <div className='flex flex-column center m-20 w-750'>
            <h3 className='m-20'>Login</h3>
            <form className='flex flex-column w-750 center' onSubmit={e=>login(e, {email, password})} >
                <TextField
                    className={classStyle.root}
                    required
                    type='email'
                    id="email"
                    label="Email"
                    variant="outlined"
                    onChange={e=>setEmail(e.target.value)}
                />
                <TextField
                    className={classStyle.root}
                    required
                    type='password'
                    id="password"
                    label="Password"
                    variant="outlined"
                    onChange={e=>setPassword(e.target.value)}
                />
                
                <input 
                    type='submit'
                    className='purple-button mt-20 h-3' 
                    onClick={e=>login(e)}
                    value='Login' />
            </form>
            <p>Don't Have an account?</p>
            <form onSubmit='/register'>
                <input value='Register' type='submit' className='flex flex-column w-750 center purple-button h-3' onClick={e=>clickRegister(e)} />
            </form>

        </div>
    )
}



const mapStateToProps = (state) => ({
    email: state.user.email,
    token: state.user.token,
    isLoggedIn: state.user.isLoggedIn,
  })
  
const mapDispatchToProps = (dispatch) => {
    return {
        login: bindActionCreators(login, dispatch),
    }
}
  
export default connect(mapStateToProps, mapDispatchToProps)(Signin)
"dependencies": {
    "@material-ui/core": "4.11.3",
    "axios": "0.21.1",
    "material-ui": "0.20.2",
    "next": "9.4.1",
    "next-redux-wrapper": "^6.0.1",
    "react": "^16.12.0",
    "react-dom": "^16.12.0",
    "react-redux": "7.1.3",
    "redux": "4.0.5",
    "redux-devtools-extension": "2.13.8",
    "redux-thunk": "2.3.0"
  },
Share Improve this question asked Feb 7, 2021 at 14:56 AvidDabblerAvidDabbler 6318 silver badges20 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 9

You need additional setup for Material-UI stylesheets in pages/_document.js to support SSR styling.


From MaterialUI v5

If you don't have a custom _document yet, create one with the following code:

import React from 'react';
import Document, { Html, Head, Main, NextScript } from 'next/document';
import createEmotionServer from '@emotion/server/create-instance';
import theme from '../src/theme';
import createEmotionCache from '../src/createEmotionCache';

class MyDocument extends Document {
    static async getInitialProps(ctx) {
        const originalRenderPage = ctx.renderPage;
        const cache = createEmotionCache();
        const { extractCriticalToChunks } = createEmotionServer(cache);

        ctx.renderPage = () =>
            originalRenderPage({
                enhanceApp: (App) => function EnhanceApp(props) {
                    return <App emotionCache={cache} {...props} />;
                }
            });

        const initialProps = await Document.getInitialProps(ctx);
        const emotionStyles = extractCriticalToChunks(initialProps.html);
        const emotionStyleTags = emotionStyles.styles.map((style) => (
            <style
                data-emotion={`${style.key} ${style.ids.join(' ')}`}
                key={style.key}
                // eslint-disable-next-line react/no-danger
                dangerouslySetInnerHTML={{ __html: style.css }}
            />
        ));

        return {
            ...initialProps,
            emotionStyleTags,
        };
    }

    render() {
        return (
            <Html lang="en">
                <Head>
                    <meta name="theme-color" content={theme.palette.primary.main} />
                    <link rel="shortcut icon" href="/static/favicon.ico" />
                    <link
                        rel="stylesheet"
                        href="https://fonts.googleapis./css?family=Roboto:300,400,500,700&display=swap"
                    />
                    {this.props.emotionStyleTags}
                </Head>
                <body>
                    <Main />
                    <NextScript />
                </body>
            </Html>
        );
    }
};

Then, in your _app.

import React from 'react';
import Head from 'next/head';
import { ThemeProvider } from '@mui/material/styles';
import CssBaseline from '@mui/material/CssBaseline';
import { CacheProvider } from '@emotion/react';
import theme from '../src/theme';
import createEmotionCache from '../src/createEmotionCache';

const clientSideEmotionCache = createEmotionCache();

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

    return (
        <CacheProvider value={emotionCache}>
            <Head>
                <meta name="viewport" content="initial-scale=1, width=device-width" />
            </Head>
            <ThemeProvider theme={theme}>
                <CssBaseline />
                <Component {...pageProps} />
            </ThemeProvider>
        </CacheProvider>
    );
}

Before MaterialUI v5

If you don't have a custom _document.js yet, create one with the following code:

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

class MyDocument extends Document {
  static async getInitialProps(ctx) {
    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()
      ]
    };
  }

  render() {
    return (
      <Html lang="en">
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

export default MyDocument;

You can then remove the server-side injected styles in your custom _app.js.

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

For further details check Material-UI official documentation.

发布评论

评论列表(0)

  1. 暂无评论