Material UI在生产环境中破坏了NextJS应用程序

8
我创建了一个使用服务器端渲染和Material UI的NextJS应用程序。在开发环境中运行良好。
当我运行“next build”时,应用程序会编译和构建而无错误。当我使用NODE_ENV = production运行它时,网页可以正常呈现,但许多功能不再起作用。例如:
1. Material UI的“Hidden”组件永远不会显示其内嵌的任何子组件,即使应该(在我的开发应用程序中,根据屏幕大小隐藏和显示某些div)。
2. 网页上的所有按钮都不起作用。这些按钮都具有"onClick"事件,它们的回调函数在单击时以某种方式修改React状态对象。然而,单击这些按钮时什么也不会发生。状态保持不变,因此我认为这些函数在单击这些click事件时从未被调用过。这同样适用于Material UI的Button组件以及普通的HTML按钮(作为JSX)。
在我的笔记本电脑上以dev模式运行时一切都完全正常。但是,当我构建NextJS应用程序并将其部署到生产模式的服务器上时,我遇到了上述问题。到目前为止,我的研究只发现了可能在构建过程中存在类名冲突的可能性(这在Material UI的FAQ页面上说过)。是否有人遇到了我所遇到的相同问题?
编辑:我刚刚启动了一个裸骨NextJS应用程序,其中仅包含一个索引页面和最小依赖项,具有一个状态参数和一个按钮以通过onClick事件修改该参数。我遇到了同样的问题。在开发中,按钮起作用,在生产中则不起作用。因此,这将是一个NextJS问题而不是Material UI问题。但这仍然无法解释为什么Material UI的“Hidden”组件始终保持隐藏状态,而不考虑屏幕大小。也许它既是Next JS又是Material UI问题。

2
你解决了这个问题吗? - Mike K
你解决了这个问题吗?我在这里提出了一个类似的问题 https://github.com/chakra-ui/chakra-ui/issues/2226#issuecomment-791625187 - Jack B
3个回答

2

我认为这可以帮助你。 在_document.js文件中。

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

export default class MyDocument extends Document {
  render() {
    return (
      <Html lang="en">
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

// `getInitialProps` belongs to `_document` (instead of `_app`),
// it's compatible with server-side generation (SSG).
MyDocument.getInitialProps = async (ctx) => {

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

并在 _app.js 中添加

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

希望它能正常工作!

1
关于第一个问题,因为你开启了 SSR,Material UI 不能在服务器端判断断点。这里有一个官方示例server-sider-rendering。您需要根据 UA 标头确定用户设备以确定页面大小。使用匹配项来确定所需显示的内容。

0

_document.js -> 用于服务器端渲染的MaterialUI样式。

import React from 'react'
import NextDocument from 'next/document'
import { ServerStyleSheet as StyledComponentSheets } from 'styled-components'
import { ServerStyleSheets as MaterialUiServerStyleSheets } from '@material-
ui/styles'

export default class Document extends NextDocument {

static async getInitialProps(ctx) {
const styledComponentSheet = new StyledComponentSheets()
const materialUiSheets = new MaterialUiServerStyleSheets()
const originalRenderPage = ctx.renderPage

try {
  ctx.renderPage = () =>
    originalRenderPage({
      enhanceApp: App => props =>
        styledComponentSheet.collectStyles(
          materialUiSheets.collect(<App {...props} />),
        ),
    })

  const initialProps = await NextDocument.getInitialProps(ctx)

  return {
    ...initialProps,
    styles: [
      <React.Fragment key="styles">
        {initialProps.styles}
        {materialUiSheets.getStyleElement()}
        {styledComponentSheet.getStyleElement()}
      </React.Fragment>,
    ],
  }
} finally {
  styledComponentSheet.seal()
}
}
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接