跳到内容
+

v5 版本中的重大变更,第一部分:样式和主题

这是一份关于 Material UI v5 中引入的重大变更以及如何从 v4 迁移的参考指南。本部分涵盖样式和主题的变更。

Material UI v5 迁移

  1. 开始使用
  2. 重大变更第一部分:样式和主题 👈 您在这里
  3. 重大变更第二部分:组件
  4. 从 JSS 迁移
  5. 问题排查

重大变更,第一部分

Material UI v5 引入了许多与 v4 相比的重大变更。许多变更可以使用代码模组自动解决,详见主要迁移指南

以下文档列出了 v5 中与样式和主题相关的所有重大变更以及如何解决这些变更。

完成本文档后,请继续阅读v5 版本中的重大变更第二部分:组件,以继续迁移过程。

将主题 styleOverrides 迁移到 Emotion

重构本地规则引用

尽管在主题中定义的样式覆盖可能部分有效,但在嵌套元素的样式设置方式上存在重要差异。

与 JSS 一起使用的 $ 语法(本地规则引用)不适用于 Emotion。您需要将这些选择器替换为有效的类选择器。

替换状态类名

 const theme = createTheme({
   components: {
     MuiOutlinedInput: {
       styleOverrides: {
         root: {
-          '&$focused': {
+          '&.Mui-focused': {
             borderWidth: 1,
           }
         }
       }
     }
   }
 });

将嵌套类选择器替换为全局类名

 const theme = createTheme({
   components: {
     MuiOutlinedInput: {
       styleOverrides: {
         root: {
-          '& $notchedOutline': {
+          '& .MuiOutlinedInput-notchedOutline': {
             borderWidth: 1,
           }
         }
       }
     }
   }
 });
+import { outlinedInputClasses } from '@mui/material/OutlinedInput';

 const theme = createTheme({
   components: {
     MuiOutlinedInput: {
       styleOverrides: {
         root: {
-          '& $notchedOutline': {
+          [`& .${outlinedInputClasses.notchedOutline}`]: {
             borderWidth: 1,
           }
         }
       }
     }
   }
 });

查看完整的全局状态类名列表

重构空格和逗号分隔值的替代语法

Emotion 不支持 JSS 支持的空格和逗号分隔值的替代的基于数组的语法。

将基于数组的值替换为基于字符串的值

之前

const theme = createTheme({
  overrides: {
    MuiBox: {
      root: {
        background: [
          ['url(image1.png)', 'no-repeat', 'top'],
          ['url(image2.png)', 'no-repeat', 'center'],
          '!important',
        ],
      },
    },
  },
});

之后

const theme = createTheme({
  components: {
    MuiBox: {
      styleOverrides: {
        root: {
          background:
            'url(image1.png) no-repeat top, url(image2.png) no-repeat center !important',
        },
      },
    },
  },
});

请务必根据需要为数值添加单位。

之前

const theme = createTheme({
  overrides: {
    MuiOutlinedInput: {
      root: {
        padding: [[5, 8, 6]],
      },
    },
  },
});

之后

const theme = createTheme({
  components: {
    MuiOutlinedInput: {
      styleOverrides: {
        root: {
          padding: '5px 8px 6px',
        },
      },
    },
  },
});

ref

重构非 ref 转发类组件

已删除对 component prop 中或作为直接 children 的非 ref 转发类组件的支持。

如果您使用的是 unstable_createStrictModeTheme 或者在 React.StrictMode 中没有看到任何与 findDOMNode 相关的警告,则无需采取任何进一步的操作。

否则,请查看 Composition 指南中的关于 refs 的注意事项部分,以了解如何迁移。此更改几乎影响所有您使用 component prop 或将 children 传递给需要 children 为元素的组件(例如 <MenuList><CustomMenuItem /></MenuList>)的情况。

修复 ref 类型特异性

对于某些组件,在传递 ref 时可能会收到类型错误。为了避免错误,您应该使用特定的元素类型。例如,Card 期望 ref 的类型为 HTMLDivElement,而 ListItem 期望其 ref 类型为 HTMLLIElement

这是一个示例

 import * as React from 'react';
 import Card from '@mui/material/Card';
 import ListItem from '@mui/material/ListItem';

 export default function SpecificRefType() {
-  const cardRef = React.useRef<HTMLElement>(null);
+  const cardRef = React.useRef<HTMLDivElement>(null);

-  const listItemRef = React.useRef<HTMLElement>(null);
+  const listItemRef = React.useRef<HTMLLIElement>(null);
   return (
     <div>
       <Card ref={cardRef}></Card>
       <ListItem ref={listItemRef}></ListItem>
     </div>
   );
 }

以下是每个组件期望的特定元素类型

@mui/material

@mui/lab

样式库

✅ 调整 CSS 注入顺序

v5 中默认使用的样式库是 Emotion

如果您正在使用 JSS 进行 Material UI 组件的样式覆盖(例如,通过 makeStyles 创建的样式),则需要注意 CSS 注入顺序。JSS <style> 元素需要在 Emotion <style> 元素之后注入到 <head> 中。

为此,您需要在组件树的顶部使用带有 injectFirst 选项的 StyledEngineProvider,如下所示

import * as React from 'react';
import { StyledEngineProvider } from '@mui/material/styles';

export default function GlobalCssPriority() {
  return (
    {/* Inject Emotion before JSS */}
    <StyledEngineProvider injectFirst>
      {/* Your component tree. Now you can override Material UI's styles. */}
    </StyledEngineProvider>
  );
}

✅ 向 createCache 添加 prepend

如果您有自定义缓存并且正在使用 Emotion 来设置应用程序的样式,它将覆盖 Material UI 提供的缓存。

要更正注入顺序,请将 prepend 选项添加到 createCache,如下所示

 import * as React from 'react';
 import { CacheProvider } from '@emotion/react';
 import createCache from '@emotion/cache';

 const cache = createCache({
   key: 'css',
+  prepend: true,
 });

 export default function PlainCssPriority() {
   return (
     <CacheProvider value={cache}>
       {/* Your component tree. Now you can override Material UI's styles. */}
     </CacheProvider>
   );
 }

主题结构

✅ 添加 adaptV4Theme 助手函数

v5 中主题的结构已更改。您需要更新其形状。为了更平滑地过渡,adaptV4Theme 助手函数允许您迭代地将一些主题更改升级到新的主题结构。

-import { createMuiTheme } from '@mui/material/styles';
+import { createTheme, adaptV4Theme } from '@mui/material/styles';

-const theme = createMuiTheme({
+const theme = createTheme(adaptV4Theme({
   // v4 theme
-});
+}));

适配器支持以下更改

移除 gutters

“gutters” 抽象概念已被证明不够常用,没有足够的价值。

-theme.mixins.gutters(),
+paddingLeft: theme.spacing(2),
+paddingRight: theme.spacing(2),
+[theme.breakpoints.up('sm')]: {
+  paddingLeft: theme.spacing(3),
+  paddingRight: theme.spacing(3),
+},

✅ 移除 px 后缀

theme.spacing 现在默认返回带有 px 单位的单个值。此更改改进了与 styled-components 和 Emotion 的集成。

之前

theme.spacing(2) => 16

之后

theme.spacing(2) => '16px'

✅ 重命名 theme.palette.type

theme.palette.type 键已重命名为 theme.palette.mode,以更好地遵循通常用于描述此功能的“暗黑模式”术语。

 import { createTheme } from '@mui/material/styles';
-const theme = createTheme({ palette: { type: 'dark' } }),
+const theme = createTheme({ palette: { mode: 'dark' } }),

更改默认 theme.palette.info 颜色

默认的 theme.palette.info 颜色已更改为在亮色和暗黑模式下都通过 AA 级可访问性标准对比度。

  info = {
-  main: cyan[500],
+  main: lightBlue[700], // lightBlue[400] in "dark" mode

-  light: cyan[300],
+  light: lightBlue[500], // lightBlue[300] in "dark" mode

-  dark: cyan[700],
+  dark: lightBlue[900], // lightBlue[700] in "dark" mode
  }

更改默认 theme.palette.success 颜色

默认的 theme.palette.success 颜色已更改为在亮色和暗黑模式下都通过 AA 级可访问性标准对比度。

  success = {
-  main: green[500],
+  main: green[800], // green[400] in "dark" mode

-  light: green[300],
+  light: green[500], // green[300] in "dark" mode

-  dark: green[700],
+  dark: green[900], // green[700] in "dark" mode
  }

更改默认 theme.palette.warning 颜色

默认的 theme.palette.warning 颜色已更改为在亮色和暗黑模式下都通过 AA 级可访问性标准对比度。

  warning = {
-  main: orange[500],
+  main: '#ED6C02', // orange[400] in "dark" mode

-  light: orange[300],
+  light: orange[500], // orange[300] in "dark" mode

-  dark: orange[700],
+  dark: orange[900], // orange[700] in "dark" mode
  }

恢复 theme.palette.text.hint 键(如果需要)

theme.palette.text.hint 键在 Material UI 组件中未使用,已被删除。如果您依赖它,可以将其添加回去

  import { createTheme } from '@mui/material/styles';

-const theme = createTheme(),
+const theme = createTheme({
+  palette: { text: { hint: 'rgba(0, 0, 0, 0.38)' } },
+});

重构组件定义

主题中的组件定义已在 components 键下重构,以便更容易找到它们。

1. props

 import { createTheme } from '@mui/material/styles';

 const theme = createTheme({
-  props: {
-    MuiButton: {
-      disableRipple: true,
-    },
-  },
+  components: {
+    MuiButton: {
+      defaultProps: {
+        disableRipple: true,
+      },
+    },
+  },
 });

2. overrides

 import { createTheme } from '@mui/material/styles';

 const theme = createTheme({
-  overrides: {
-    MuiButton: {
-      root: { padding: 0 },
-    },
-  },
+  components: {
+    MuiButton: {
+      styleOverrides: {
+        root: { padding: 0 },
+      },
+    },
+  },
 });

@mui/styles

更新 ThemeProvider 导入

如果您正在将 @mui/styles 中的实用程序与 @mui/material 一起使用,则应将 ThemeProvider 的使用从 @mui/styles 替换为从 @mui/material/styles 导出的 ThemeProvider

这样,上下文中提供的主题将在从 @mui/styles 导出的样式实用程序(如 makeStyleswithStyles 等)以及 Material UI 组件中都可用。

-import { ThemeProvider } from '@mui/styles';
+import { ThemeProvider } from '@mui/material/styles';

请确保在应用程序的根目录中添加 ThemeProvider,因为 defaultTheme 在来自 @mui/styles 的实用程序中不再可用。

✅ 为 DefaultTheme 添加模块扩展(TypeScript)

@mui/styles 包不再是 @mui/material/styles 的一部分。

如果您正在将 @mui/styles@mui/material 一起使用,则需要为 DefaultTheme 添加模块扩展。

// in the file where you are creating the theme (invoking the function `createTheme()`)
import { Theme } from '@mui/material/styles';

declare module '@mui/styles' {
  interface DefaultTheme extends Theme {}
}

@mui/material/colors

✅ 更改颜色导入

超过一级的嵌套导入是私有的。例如,您不能再从 @mui/material/colors/red 导入 red

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

@mui/material/styles

✅ 将 fade 重命名为 alpha

fade() 已重命名为 alpha(),以更好地描述其功能。

之前的名称在输入颜色已经具有 alpha 值时会引起混淆。助手函数会覆盖颜色的 alpha 值。

-import { fade } from '@mui/material/styles';
+import { alpha } from '@mui/material/styles';

  const classes = makeStyles(theme => ({
-  backgroundColor: fade(theme.palette.primary.main, theme.palette.action.selectedOpacity),
+  backgroundColor: alpha(theme.palette.primary.main, theme.palette.action.selectedOpacity),
  }));

✅ 更新 createStyles 导入

@mui/material/styles 中的 createStyles 函数已移动到从 @mui/styles 导出的函数。这对于删除 Material UI npm 包中对 @mui/styles 的依赖是必要的。

-import { createStyles } from '@mui/material/styles';
+import { createStyles } from '@mui/styles';

✅ 更新 createGenerateClassName 导入

createGenerateClassName 函数不再从 @mui/material/styles 导出。如果您需要继续使用它,可以从已弃用的 @mui/styles 包中导入它。

-import { createGenerateClassName } from '@mui/material/styles';
+import { createGenerateClassName } from '@mui/styles';

要生成不使用 @mui/styles 的自定义类名,请查看 ClassName Generator 以获取更多详细信息。

✅ 重命名 createMuiTheme

函数 createMuiTheme 已重命名为 createTheme(),以便更直观地与 ThemeProvider 一起使用。

-import { createMuiTheme } from '@mui/material/styles';
+import { createTheme } from '@mui/material/styles';

-const theme = createMuiTheme({
+const theme = createTheme({

✅ 更新 MuiThemeProvider 导入

MuiThemeProvider 组件不再从 @mui/material/styles 导出。请改用 ThemeProvider

-import { MuiThemeProvider } from '@mui/material/styles';
+import { ThemeProvider } from '@mui/material/styles';

✅ 更新 jssPreset 导入

jssPreset 对象不再从 @mui/material/styles 导出。如果您需要继续使用它,可以从已弃用的 @mui/styles 包中导入它。

-import { jssPreset } from '@mui/material/styles';
+import { jssPreset } from '@mui/styles';

✅ 更新 makeStyles 导入

由于 Material UI v5 不使用 JSS,因此基于 JSS 的 makeStyles 实用程序不再由 @mui/material/styles 导出。在将您的应用程序从 JSS 迁移出去时,您可以暂时从 @mui/styles/makeStyles 导入此已弃用的实用程序,然后再进一步重构您的组件。

请确保在应用程序的根目录中添加 ThemeProvider,因为 defaultTheme 不再可用。

如果您正在将此实用程序与 @mui/material 一起使用,建议您改用 @mui/material/styles 中的 ThemeProvider 组件。

-import { makeStyles } from '@mui/material/styles';
+import { makeStyles } from '@mui/styles';
+import { createTheme, ThemeProvider } from '@mui/material/styles';

+const theme = createTheme();
  const useStyles = makeStyles((theme) => ({
    background: theme.palette.primary.main,
  }));
  function Component() {
    const classes = useStyles();
    return <div className={classes.root} />
  }

  // In the root of your app
  function App(props) {
-  return <Component />;
+  return <ThemeProvider theme={theme}><Component {...props} /></ThemeProvider>;
  }

✅ 更新 ServerStyleSheets 导入

ServerStyleSheets 组件不再从 @mui/material/styles 导出。如果您需要继续使用它,可以从已弃用的 @mui/styles 包中导入它。

-import { ServerStyleSheets } from '@mui/material/styles';
+import { ServerStyleSheets } from '@mui/styles';

styled

由于 Material UI v5 不使用 JSS,因此 @mui/material/styles 导出的基于 JSS 的 styled 实用程序已被替换为等效的基于 Emotion 的实用程序,该实用程序不向后兼容。在将您的应用程序从 JSS 迁移出去时,您可以暂时从已弃用的 @mui/styles 包中导入基于 JSS 的实用程序,然后再进一步重构您的组件。

请确保在应用程序的根目录中添加 ThemeProvider,因为 defaultTheme 不再可用。

如果您正在将此实用程序与 @mui/material 一起使用,建议您改用 @mui/material/styles 中的 ThemeProvider 组件。

-import { styled } from '@mui/material/styles';
+import { styled } from '@mui/styles';
+import { createTheme, ThemeProvider } from '@mui/material/styles';

+const theme = createTheme();
  const MyComponent = styled('div')(({ theme }) => ({ background: theme.palette.primary.main }));

  function App(props) {
-  return <MyComponent />;
+  return <ThemeProvider theme={theme}><MyComponent {...props} /></ThemeProvider>;
  }

✅ 更新 StylesProvider 导入

StylesProvider 组件不再从 @mui/material/styles 导出。如果您需要继续使用它,可以从已弃用的 @mui/styles 包中导入它。

-import { StylesProvider } from '@mui/material/styles';
+import { StylesProvider } from '@mui/styles';

✅ 更新 useThemeVariants 导入

useThemeVariants hook 不再从 @mui/material/styles 导出。如果您需要继续使用它,可以从已弃用的 @mui/styles 包中导入它。

-import { useThemeVariants } from '@mui/material/styles';
+import { useThemeVariants } from '@mui/styles';

✅ 更新 withStyles 导入

由于 Material UI v5 不使用 JSS,因此基于 JSS 的 withStyles 实用程序不再由 @mui/material/styles 导出。在将您的应用程序从 JSS 迁移出去时,您可以暂时从 @mui/styles/withStyles 导入此已弃用的实用程序,然后再进一步重构您的组件。

请确保在应用程序的根目录中添加 ThemeProvider,因为 defaultTheme 不再可用。

如果您正在将此实用程序与 @mui/material 一起使用,则应改用 @mui/material/styles 中的 ThemeProvider 组件。

-import { withStyles } from '@mui/material/styles';
+import { withStyles } from '@mui/styles';
+import { createTheme, ThemeProvider } from '@mui/material/styles';

+const defaultTheme = createTheme();
  const MyComponent = withStyles((props) => {
    const { classes, className, ...other } = props;
    return <div className={clsx(className, classes.root)} {...other} />
  })(({ theme }) => ({ root: { background: theme.palette.primary.main }}));

  function App() {
-  return <MyComponent />;
+  return <ThemeProvider theme={defaultTheme}><MyComponent /></ThemeProvider>;
  }

✅ 将 innerRef 替换为 ref

innerRef prop 替换为 ref prop。Refs 现在会自动转发到内部组件。

  import * as React from 'react';
  import { withStyles } from '@mui/styles';

  const MyComponent = withStyles({
    root: {
      backgroundColor: 'red',
    },
  })(({ classes }) => <div className={classes.root} />);

  function MyOtherComponent(props) {
    const ref = React.useRef();
-  return <MyComponent innerRef={ref} />;
+  return <MyComponent ref={ref} />;
  }

更新 withTheme 导入

withTheme HOC 实用程序已从 @mui/material/styles 包中删除。您可以改用 @mui/styles/withTheme

请确保在应用程序的根目录中添加 ThemeProvider,因为 defaultTheme 不再可用。

如果您正在将此实用程序与 @mui/material 一起使用,建议您改用 @mui/material/styles 中的 ThemeProvider 组件。

-import { withTheme } from '@mui/material/styles';
+import { withTheme } from '@mui/styles';
+import { createTheme, ThemeProvider } from '@mui/material/styles';

+const theme = createTheme();
  const MyComponent = withTheme(({ theme }) => <div>{theme.direction}</div>);

  function App(props) {
-  return <MyComponent />;
+  return <ThemeProvider theme={theme}><MyComponent {...props} /></ThemeProvider>;
  }

✅ 移除 withWidth

此 HOC 已移除。如果您需要此功能,可以尝试使用 useMediaQuery hook 的替代方案

@mui/icons-material

减小 GitHub 图标大小

GitHub 图标的宽度从 24px 减小到 22px,以匹配其他图标的大小。

@material-ui/pickers

我们有一个专门的页面用于将 @material-ui/pickers 迁移到 v5。

系统

✅ 重命名 gap props

以下系统函数和属性已重命名,因为它们被认为是已弃用的 CSS

  • gridGap 变为 gap
  • gridRowGap 变为 rowGap
  • gridColumnGap 变为 columnGap

✅ 向 gap props 添加间距单位

gaprowGapcolumnGap 中使用间距单位。如果您之前使用的是数字,则需要提及 px 以绕过使用 theme.spacing 的新转换。

  <Box
-  gap={2}
+  gap="2px"
  >

css prop 替换为 sx,以避免与 styled-components 和 Emotion 的 css prop 冲突。

-<Box css={{ color: 'primary.main' }} />
+<Box sx={{ color: 'primary.main' }} />