跳到主要內容
+

疑難排解

本文檔涵蓋從 Material UI v4 遷移至 v5 時已知的問題和常見問題。

Material UI v5 遷移

  1. 開始使用
  2. 重大變更第一部分:樣式與主題
  3. 重大變更第二部分:組件
  4. 從 JSS 遷移
  5. 疑難排解 👈 您在這裡

遷移至 v5 後樣式損壞

在您完成遷移過程中的所有步驟後,組件樣式可能損壞的原因有兩個。

首先,檢查您是否已正確配置 StyledEngineProvider,如樣式庫章節所示。

如果 StyledEngineProvider 已在您的應用程式頂部使用,但樣式仍然損壞,則可能是您的應用程式中仍然有 @material-ui/core

這可能是由於應用程式中其他依賴項仍然依賴 Material UI v4 所導致的。

要檢查這一點,請執行 npm ls @material-ui/core (或 yarn why @material-ui/core)。如果您的專案包含此類依賴項,您將看到如下所示的列表

$ npm ls @material-ui/core
project@0.1.0 /path/to/project
└─┬  @mui/x-data-grid@4.0.0
  └── @material-ui/core@4.12.3

上面的輸出表明 @material-ui/core@mui/x-data-grid 的依賴項。

在這個特定的例子中,您需要將 @mui/x-data-grid 的版本提升到 v5,以便它依賴於 @mui/material 而不是 @material-ui/core

Storybook 和 Emotion

如果您的專案使用 Storybook v6.x,您將需要更新 .storybook/main.js webpack 配置,以使用最新版本的 Emotion

// .storybook/main.js

const path = require('path');
const toPath = (filePath) => path.join(process.cwd(), filePath);

module.exports = {
  webpackFinal: async (config) => {
    return {
      ...config,
      resolve: {
        ...config.resolve,
        alias: {
          ...config.resolve.alias,
          '@emotion/core': toPath('node_modules/@emotion/react'),
          'emotion-theming': toPath('node_modules/@emotion/react'),
        },
      },
    };
  },
};

接下來,更新 .storybook/preview.js 以防止 Storybook 的 Docs 標籤顯示空白頁面

// .storybook/preview.js

import { ThemeProvider, createTheme } from '@mui/material/styles';
import { ThemeProvider as Emotion10ThemeProvider } from 'emotion-theming';

const defaultTheme = createTheme(); // or your custom theme

const withThemeProvider = (Story, context) => {
  return (
    <Emotion10ThemeProvider theme={defaultTheme}>
      <ThemeProvider theme={defaultTheme}>
        <Story {...context} />
      </ThemeProvider>
    </Emotion10ThemeProvider>
  );
};

export const decorators = [withThemeProvider];

// ...other storybook exports

無法讀取 null 的屬性 scrollTop

此錯誤來自於 FadeGrowSlideZoom 組件,原因是缺少 DOM 節點。

確保子組件將 ref 轉發到自訂組件的 DOM

// Ex. 1-1 ❌ This will cause an error because the Fragment is not a DOM node:
<Fade in>
  <React.Fragment>
    <CustomComponent />
  </React.Fragment>
</Fade>
// Ex. 1-2 ✅ Add a DOM node such as this div:
<Fade in>
  <div>
    <CustomComponent />
  </div>
</Fade>
// Ex. 2-1 ❌ This will cause an error because `CustomComponent` does not forward `ref` to the DOM:
function CustomComponent() {
  return <div>...</div>;
}

<Fade in>
  <CustomComponent />
</Fade>;
// Ex. 2-2 ✅ Add `React.forwardRef` to forward `ref` to the DOM:
const CustomComponent = React.forwardRef(function CustomComponent(props, ref) {
  return (
    <div ref={ref}>
      ...
    </div>
  )
})

<Fade in>
  <CustomComponent />
</Fade>

有關更多詳細資訊,請查看 GitHub 上的這個 issue

[Types] 屬性 "palette", "spacing" 在類型 'DefaultTheme' 上不存在

出現此錯誤的原因是 makeStyles 現在從 @mui/styles 套件匯出,該套件不了解核心套件中的 Theme

要解決此問題,您需要使用核心套件中的 Theme 來擴充 @mui/styles 中的 DefaultTheme (空物件)。

閱讀更多關於模組擴充的資訊,請參閱官方 TypeScript 文件

TypeScript

將此程式碼片段添加到您的主題檔案

// it could be your App.tsx file or theme file that is included in your tsconfig.json
import { Theme } from '@mui/material/styles';

declare module '@mui/styles/defaultTheme' {
  // eslint-disable-next-line @typescript-eslint/no-empty-interface (remove this line if you don't have the rule enabled)
  interface DefaultTheme extends Theme {}
}

JavaScript

如果您正在使用像 VS Code 這樣的 IDE,它可以從 d.ts 檔案推斷類型,請在您的 src 資料夾中建立 index.d.ts 並添加以下程式碼行

// index.d.ts
declare module '@mui/private-theming' {
  import type { Theme } from '@mui/material/styles';

  interface DefaultTheme extends Theme {}
}

[Jest] SyntaxError: Unexpected token 'export'

@mui/material/colors/red 自 v1.0.0 以來被視為私有。要修正此錯誤,您必須替換導入。有關更多詳細資訊,請參閱 這個 GitHub issue

我們建議使用這個 codemod 來修正您專案中的所有導入

npx @mui/codemod@latest v5.0.0/optimal-imports <path>

您可以像這樣手動修正它

-import red from '@mui/material/colors/red';
+import { red } from '@mui/material/colors';

makeStyles - TypeError: Cannot read property 'drawer' of undefined

當在 <ThemeProvider> 範圍之外呼叫 useStyleswithStyles 時,會發生此錯誤,如下例所示

import * as React from 'react';
import { ThemeProvider, createTheme } from '@mui/material/styles';
import makeStyles from '@mui/styles/makeStyles';
import Card from '@mui/material/Card';
import CssBaseline from '@mui/material/CssBaseline';

const useStyles = makeStyles((theme) => ({
  root: {
    display: 'flex',
    backgroundColor: theme.palette.primary.main,
    color: theme.palette.common.white,
  },
}));

const theme = createTheme();

function App() {
  const classes = useStyles(); // ❌ called outside of ThemeProvider
  return (
    <ThemeProvider theme={theme}>
      <CssBaseline />
      <Card className={classes.root}>...</Card>
    </ThemeProvider>
  );
}

export default App;

您可以透過將 useStyles 移動到另一個組件內部來修正此問題,以便在 <ThemeProvider> 下呼叫它

// ...imports

function AppContent(props) {
  const classes = useStyles(); // ✅ This is safe because it is called inside ThemeProvider
  return <Card className={classes.root}>...</Card>;
}

function App(props) {
  return (
    <ThemeProvider theme={theme}>
      <CssBaseline />
      <AppContent {...props} />
    </ThemeProvider>
  );
}

export default App;

TypeError: Cannot read properties of undefined (reading 'pxToRem')

此錯誤是由於嘗試存取空主題而產生的。

請確保您已解決以下問題

  1. styled 應僅從 @mui/material/styles 導入 (如果您未使用獨立的 @mui/system)
import { styled } from '@mui/material/styles';
  1. useStyles 無法在 <ThemeProvider> 之外呼叫。要解決此問題,請按照本節中的說明操作。

有關更多詳細資訊,請參閱 這個 GitHub issue

仍然有問題?

如果您遇到此處未涵蓋的問題,請使用以下標題格式建立一個 GitHub issue[Migration] 您的問題摘要