【问题标题】:Material UI breaks NextJS app in productionMaterial UI 在生产中破坏了 NextJS 应用程序
【发布时间】:2020-11-29 03:10:19
【问题描述】:

我创建了一个使用服务器端渲染和 Material UI 的 NextJS 应用程序。它在开发中运行良好。

当我运行“下一个构建”时,应用程序编译和构建没有错误。当我使用 NODE_ENV=production 运行它时,网页呈现得很好,但许多功能不再起作用。例如:

  1. Material UI 的“隐藏”组件从不显示任何嵌套在其中的子组件,即使它应该显示(在我的开发应用程序中,它会根据屏幕大小隐藏和显示某些 div)。

  2. 网页上的按钮都不起作用。所有这些按钮都有“onClick”事件,其回调函数在单击时以某种方式修改 React 状态对象。然而,当这些被点击时,什么也没有发生。状态保持不变,所以我假设当这些点击事件发生时这些函数永远不会被调用。这适用于 Material UI 的 Button 组件以及普通的旧 HTML 按钮(如 JSX)。

当我在笔记本电脑上以开发模式运行此程序时,一切正常。但是,当我构建 NextJS 应用程序并以生产模式将其部署到服务器时,我遇到了上面列出的问题。到目前为止,我的研究只发现了构建过程中类名冲突的可能性(这在 Material UI 的常见问题页面上已经说过)。有没有人和我一样的问题?

编辑:我刚刚启动了一个准系统 NextJS 应用程序,其中仅包含一个索引页面和最小依赖项,具有一个状态参数和一个按钮,用于通过 onClick 事件修改参数。我有同样的问题。该按钮在开发中有效,但在生产中无效。所以这将是 NextJS 问题而不是 Material UI 问题。但这仍然不能解释为什么 Material UI 的“隐藏”组件始终保持隐藏,无论屏幕大小如何。可能是 Next JS 和 Material UI 的问题。

【问题讨论】:

标签: reactjs material-ui next.js production-environment


【解决方案1】:

我认为这可以帮助你。 在 _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);
  }
}, []);

希望它有效!

【讨论】:

    【解决方案2】:

    关于第一个问题,因为你打开了ssr,所以素材ui无法判断服务器端的断点。这是官方的例子。server-sider-rendering.您需要根据 UA 标头确定用户设备以确定页面大小。使用匹配来确定您需要显示的内容

    【讨论】:

      【解决方案3】:

      _document.js -> SSR 的 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()
      }
      }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-06-21
        • 2018-10-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-04-12
        • 2016-10-03
        相关资源
        最近更新 更多