【问题标题】:Material UI: Styles flicker in and disappearMaterial UI:样式闪烁并消失
【发布时间】:2020-03-06 13:39:05
【问题描述】:

样式可能会出现 50 毫秒,然后在此 SSR 应用的以下代码中消失。我很好奇是什么原因造成的。

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

样式消失后,会留下一个纯 HTML 按钮。

我相信 Next.js 是造成这种情况的原因。我检查了 Next.js 文件并将 next/babel 加载器添加到 .babelrc。除此之外,我只看到了其他相关的变化。这是在 /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()],
  };
};

尝试解决的问题

  1. 重启服务器

问题没有变化。

  1. 强制刷新 Chrome 78 (CTRL + F5)

没有变化。

理论

我认为存在服务器端问题。客户端和服务器应该在同一台机器上,localhost。这将解释正确的初始结果(客户端初始 UI)然后被服务器更新覆盖。

更新 1

忘了说我也更新了/pages/_app.js。这是更新的部分:

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);
    }
  }

【问题讨论】:

    标签: reactjs material-ui next.js


    【解决方案1】:

    TLDR; 如果您正在运行生产构建,请确保将 NODE_ENV 设置为生产,例如:NODE_ENV=production npm start


    对我来说,这仅发生在我的机器上,使用 npm run build 创建生产版本,然后使用 npm start 运行它。

    奇怪的是为什么服务器呈现的响应使用开发风格的类,例如 makeStyles-root-123 而不是 https://material-ui.com/styles/advanced/#class-names 解释的 jss123

    很明显,服务器的某些部分就像我们仍处于开发环境中一样。为了解决这个问题,我尝试将 NODE_ENV 设置为“生产”来启动生产构建,但问题就消失了。

    【讨论】:

      【解决方案2】:

      对我来说,这个错误的根本原因是在服务器端渲染文档期间生成的类与水合后生成的样式不匹配。

      解决此问题的一种方法是在隐藏后强制重新渲染。

      一种方法是更新组件上的 key prop。

      // inside your component
      const [key, setKey] = React.useState(0);
      
      React.useEffect(() => {
        setKey(1);
      }, []);
      
      return (<MyComponent key={}key />)
      

      我的完整_app.tsx 文件:

      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>
        );
      }
      

      【讨论】:

      • +1:最终为我修复它的块是:const generateClassName = createGenerateClassName({ productionPrefix: 'myclasses-' });,我在任何其他示例中都没有提到它。谢谢!
      • 如果您正在进行生产构建,请确保您的 NODE_ENV 设置为生产 - 如果没有上述内容,这很可能会解决您的问题。
      【解决方案3】:

      通过注释掉服务器的代码暂时解决jssStyles

      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);
        //   }
        // }
      

      如果有人知道为什么此代码包含在示例中,请发表评论。这一定是有原因的。 https://github.com/mui-org/material-ui/blob/master/examples/nextjs/pages/_app.js

      【讨论】:

      • 尝试更新到最新版本(4.9.0)也遇到了这个问题。删除了这段代码,但对我没有帮助。移回旧版本,该版本有效 - "@material-ui/core": "4.8.1", "@material-ui/styles": "4.8.2"
      • 这是为了防止 FOUC(无样式内容的闪烁),因为样式是在水合后添加的。如果您删除了该块(因此保留了服务器端样式),您应该注意到开发控制台中的重复样式。至少那是我的经历
      • 关于 FOUC 和服务器端样式的 MUI 文档:mui.com/guides/server-rendering/#heading-mui-on-the-server
      猜你喜欢
      • 2020-10-03
      • 1970-01-01
      • 2011-03-14
      • 2015-08-03
      • 1970-01-01
      • 2020-09-13
      • 2021-02-06
      • 1970-01-01
      相关资源
      最近更新 更多