v5 版本中的重大变更,第一部分:样式和主题
这是一份关于 Material UI v5 中引入的重大变更以及如何从 v4 迁移的参考指南。本部分涵盖样式和主题的变更。
Material UI v5 迁移
- 开始使用
- 重大变更第一部分:样式和主题 👈 您在这里
- 重大变更第二部分:组件
- 从 JSS 迁移
- 问题排查
重大变更,第一部分
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
- Accordion -
HTMLDivElement
- Alert -
HTMLDivElement
- Avatar -
HTMLDivElement
- ButtonGroup -
HTMLDivElement
- Card -
HTMLDivElement
- Dialog -
HTMLDivElement
- ImageList -
HTMLUListElement
- List -
HTMLUListElement
- Tab -
HTMLDivElement
- Tabs -
HTMLDivElement
- ToggleButton -
HTMLButtonElement
@mui/lab
- Timeline -
HTMLUListElement
样式库
✅ 调整 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
导出的样式实用程序(如 makeStyles
、withStyles
等)以及 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 添加间距单位
在 gap
、rowGap
和 columnGap
中使用间距单位。如果您之前使用的是数字,则需要提及 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' }} />