材质用户界面:样式闪烁并消失

时间:2019-11-10 18:24:53

标签: reactjs material-ui next.js

样式可能会持续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);
    }
  }

3 个答案:

答案 0 :(得分:7)

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

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

一种方法是更新组件上的关键道具。

// 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 :(得分: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设置为“ production”来开始生产构建,问题就解决了。

答案 2 :(得分:0)

暂时通过注释掉代码来删除服务器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