首页
/ Material UI v5 迁移实战指南:为什么你应该立刻从 v4 升级

Material UI v5 迁移实战指南:为什么你应该立刻从 v4 升级

2026-09-07 10:18:49作者:董斯意

说明:本文对应仓库中发布于 2022 年 6 月的官方博客 mui-core-v5-migration-update.md。文中关于迁移命令、破坏性变更与代码示例的描述,均结合当前仓库中完整的 v4 → v5 迁移文档 与源码进行了核实与扩充。

导读

本文面向仍然停留在 Material UI v4、犹豫是否升级到 v5 的开发者。你将了解 v5 五大核心升级点的技术原理(React 18 支持、Emotion 样式引擎、sx prop、TypeScript IntelliSense、CSS variables 远景),并掌握仓库官方文档沉淀下来的一整套低摩擦升级路径:从版本要求、包重命名、peer 依赖安装,到用 @mui/codemod 自动改写破坏性变更。读完本文,你可以结合仓库中完整的 迁移指南 为自己的项目制定一份可落地的 v5 升级计划。

背景:v5 已发布,仍有大量用户停留在 v4

Material UI 于 2021 年底正式发布了 v5(详见仓库中的 v5 发布公告)。彼时官方观察到,尽管 v5 包含大量改进,仍有一部分用户迟迟没有迁移。官方判断,犹豫的主要原因在于:v5 相对 v4 包含大量破坏性变更(breaking changes),迁移工作量看起来很大

为了降低这种顾虑,官方对 v4 → v5 迁移文档 进行了整体重构,把它组织成一套循序渐进的多步骤系列,减少升级过程中的摩擦。

需要说明的是,当前仓库主线的 Material UI 版本已经演进到 v9(例如 packages/mui-material/package.json 中版本号为 9.4.0),v4 → v5 迁移属于历史升级路径。但 v5 引入的许多设计(sx prop、Emotion 化、CSS 变量支持等)至今仍是现代 Material UI 的基石,理解这次迁移对读懂后续 v6/v7/v9 演进仍然非常有价值。仓库中该系列迁移文档也完整保留在 docs/data/material/migration/migration-v4/ 目录下。

官方重构后的迁移文档体系

在动手升级前,先了解官方迁移文档的完整骨架。这套多部分系列共五篇(均保留在仓库中),推荐按顺序阅读、逐步执行:

  1. 开始迁移:版本要求、安装新包、替换 import、运行 codemod;
  2. 破坏性变更(一):样式与主题
  3. 破坏性变更(二):组件
  4. 从 JSS 迁移到 Emotion(可选但推荐);
  5. 疑难排查 Troubleshooting

官方给出的执行建议非常明确:每完成一步就运行一次应用、确认无报错并提交一次小的 commit,再进入下一步,从而保证整个迁移过程始终处于可控状态。遇到文档未覆盖的问题,可按 [Migration] 问题摘要 的标题格式反馈。

为什么应该尽快升级到 v5:五大核心理由

1. 对 React 18 的完整支持

v5 是当时唯一完整支持 React 18 的 Material UI 版本。React 18 引入的并发渲染(Concurrent Rendering)等能力,只有在完整适配的组件库上才能可靠使用。如果你希望使用新版本 React 特性,就必须升级。

从仓库中 v4 → v5 迁移文档 可以看到具体的版本门槛提升:

  • 最低支持的 React 版本从 v16.8.0 提升到 v17.0.0(React 18 是 v5 时代的主流目标);
  • 最低支持的 TypeScript 版本从 v3.2 提升到 v3.5
  • 如果项目使用 react-scripts@types/react@types/react-dom,也需要同步更新。

作为旁证,当前仓库中 packages/mui-material/package.jsonpeerDependencies 声明了 "react": "^17.0.0 || ^18.0.0 || ^19.0.0",说明这条以 React 17 起步、面向新版本 React 的支持路线被一直延续了下来。

2. 全新样式引擎:用 Emotion 取代 JSS

v5 最大的架构级变更,是用 Emotion 取代 JSS 成为默认样式引擎。这一变更的动机与演进细节最早记录在官方 RFC(issue #22342)中。它带来两个直接收益:

  • 动态样式(dynamic styles)的性能显著提升:Emotion 在运行时针对动态样式做了大量优化;
  • 更好的开发体验(DX):为多年来社区反复要求的定制能力铺路,例如自定义样式工具属性(style utility props)、颜色变体(color variants)与自定义主题变体(theme variants)。

Material UI 仓库中样式引擎 RFC issue 的截图

仓库中 从 JSS 迁移的独立文档 明确指出:你不需要在升级当天就把全部 JSS 代码改写掉。新样式引擎是 100% 可渐进式采用的——在迁移组件期间,JSS(通过 @mui/styles 提供 makeStyleswithStyles)与 Emotion 可以共存于同一个应用。官方为此还专门提供了 Next.js + SSR 下 Emotion 与 JSS 共存的示例项目(仓库中保留在 examples/material-ui-nextjs-ts-v4-v5-migration/)。

需要特别提醒的边界事实:当时的 v5 迁移指南中,styled-components 也可作为可选替代方案,但官方明确记录了一个 SSR 场景下 Babel 插件的已知问题,因此默认强烈推荐使用 Emotion。Emotion 因此成为 v5 起不可绕开的 peer dependency——当前仓库中 packages/mui-material/package.json 仍声明 @emotion/react@^11.5.0@emotion/styled@^11.3.0 为 peer 依赖。

渐进式迁移 JSS 的两条路径

仓库的 migrating-from-jss.md 给出了两条渐进迁移路径:

路径一:使用 codemod 自动转换到 styled API

npx @mui/codemod@latest v5.0.0/jss-to-styled <path>

该 codemod 会把 makeStyles 调用改写为 styled 组件。官方特别提示:这种自动改写会提升 CSS 优先级(specificity),而且并非所有情况都能完美覆盖,建议先在小范围文件上试跑、人工检查后再继续。它生成的代码形态大致是:用 ${PREFIX}-root 这类带前缀的 class 名声明 classes 映射,再把根节点替换为 styled('div') 生成的 Root 组件。

路径二:手动迁移到 sx API 或 styled API

官方推荐在"创建响应式样式、覆盖少量 CSS"这类场景优先使用 sx prop 而非 styled(),因为 styled() 对一次性样式来说属于过度设计。下方是官方示例中的手动迁移形态(theme.spacingtheme.shadows 等主题令牌在两种写法间一一对应):

 import Chip from '@mui/material/Chip';
-import makeStyles from '@mui/styles/makeStyles';
+import Box from '@mui/material/Box';

-const useStyles = makeStyles((theme) => ({
-  wrapper: {
-    display: 'flex',
-  },
-  chip: {
-    padding: theme.spacing(1, 1.5),
-    boxShadow: theme.shadows[1],
-  }
-}));

 function App() {
-  const classes = useStyles();
   return (
-    <div className={classes.wrapper}>
+    <Box sx={{ display: 'flex' }}>
       {/* ... */}
-      <Chip className={classes.chip} />
+      <Chip sx={{ padding: (theme) => theme.spacing(1, 1.5) }} />
-    </div>
+    </Box>
   );
 }

3. 更好的定制工具:sx prop

v5 引入的 sx prop 是这篇文章最值得展开的实践性亮点。它允许你直接对单个组件应用样式规则,而无需动用整套 styled() API。sx 处理的是一套 CSS 超集,意味着如果你已熟悉 CSS,几乎可以零成本上手。

官方博客给出的完整示例(可直接复制运行)如下:

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

export default function BoxSx() {
  return (
    <Box
      sx={{
        width: 300,
        height: 300,
        backgroundColor: 'primary.dark',
        '&:hover': {
          backgroundColor: 'primary.main',
          opacity: [0.9, 0.8, 0.7],
        },
      }}
    />
  );
}

这段代码展示了 sx 的三种关键能力,值得逐一展开说明:

  • 直接消费主题令牌primary.darkprimary.main 直接引用主题调色板,无需手工拼接颜色值;
  • 嵌套选择器'&:hover' 用于书写伪类样式,作用域天然局限在当前组件上;
  • 数组形式的响应式值opacity: [0.9, 0.8, 0.7] 按照 breakpoints 从小到大依次生效,等价于手写多组 media query,是官方文档中推荐的创建响应式样式的方式。

从源码实现看,sx 的底层逻辑位于 packages/mui-system/src/styleFunctionSx/styleFunctionSx.js:它把传入的样式对象按属性名拆解(如 spacing、palette、typography、breakpoints 等系统模块),逐条转成真实的 CSS 规则,并支持通过 extendSxPropsx 展开到元素上。换句话说,sx 并不是某个组件的特例,而是整套 mui-system 的通用样式机制,因此 Box、Typography、Button 乃至所有 v5 组件都天然支持它。主题令牌类(如 primary.dark)之所以可用,正是因为它先解析自主题的调色板对象。

4. TypeScript 化的 prop 说明:IntelliSense 内联提示

v5 把所有组件的 prop 描述都改写为 TypeScript 定义书写,这意味着你在 IDE 里把鼠标悬停在某个 prop 上时,就能看到其用法说明、类型与默认值,不必再离开代码去查官方文档。这类"文档即类型"的工程化改进大幅提升了日常开发效率。

IDE 中悬停 Material UI Badge 组件 prop 时弹出的 IntelliSense 提示截图

这一能力对 v5 而言属于"开箱即得"——只要项目本身启用了 TypeScript 语言服务,就能享受到组件自带 JSDoc/类型注释的补全与提示。

5. 远景:可选的 CSS variables 支持

在 v5 发布时,CSS variables(自定义属性)被官方列为"即将到来"(upcoming)的能力,它有望解决大量定制化痛点,其中最常被社区提及的就是 暗色模式首屏闪烁(dark mode flashing)问题——传统上暗色主题的切换发生在客户端 JS 执行之后,用户刷新页面时会先看到亮色再跳变到暗色;而通过把主题令牌下推到 CSS 变量、在 HTML 层直接注入,可以在首帧就应用正确主题。

这项能力在 v5 中设计为 opt-in(按需开启),用户升级到 v5 后不需要一次性接受全部变动。当时社区可在 issue #32049 中追踪其落地进度。作为佐证,当前仓库中 createTheme 的实现 仍保留着 cssVariables?: boolean | Pick<CssVarsThemeOptions, CssVarsConfigList> 参数(默认值为 false),说明这条"主题层支持 CSS 变量"的设计路线已从当年的远景变成了仓库中真实可配置的能力。

现在就升级:官方迁移文档中的可执行步骤

结合仓库中重构后的 migration-v4.md,官方给出的升级动线如下,按顺序执行即可。

第一步:升级 React 与 TypeScript

如果你的 React 低于 17.0.0,先升级基础依赖(建议至少 @material-ui/core@^4.11.2 + react@^17.0.0):

npm install @material-ui/core@^4.11.2 react@^17.0.0

同时确保 react-scripts@types/react@types/react-dom 版本足够新。官方提示:完成每一步后都要确认应用无报错并提交 commit。

第二步:在根部配置好 ThemeProvider

升级到 v5 前,请确保应用根部与测试中都包裹了 ThemeProvider(即便使用默认主题也要包),并避免在 ThemeProvider 之外调用 useStyles。原因在于:过渡期内你仍会通过废弃的 @mui/styles 包使用 JSS 工具(makeStyles 等),而该包强依赖 ThemeProvider 上下文。

import { ThemeProvider, createMuiTheme, makeStyles } from '@material-ui/core/styles';

const theme = createMuiTheme();

function App() {
  // ❌ 若写成 const classes = useStyles(),请把它移入被 <ThemeProvider /> 包裹的组件内部
  return <ThemeProvider theme={theme}>{children}</ThemeProvider>;
}

第三步:安装 v5 包、替换 import 并清理旧包

按官方命名变更,v5 起所有包名从 @material-ui/* 改为 @mui/*。核心映射关系包括:

旧包(v4) 新包(v5)
@material-ui/core @mui/material
@material-ui/styles @mui/styles
@material-ui/icons @mui/icons-material
@material-ui/lab @mui/lab
@material-ui/system @mui/system
@material-ui/unstyled @mui/base

安装新包,同时补上 Emotion peer 依赖:

npm install @mui/material @mui/styles
npm install @emotion/react @emotion/styled

如果使用 @material-ui/lab@material-ui/icons,分别安装 @mui/lab@mui/icons-material;日期时间选择器(pickers)在 v5 中已移交到 MUI X 产品线,请迁移到 @mui/x-date-pickers。确认应用仍可运行后,再安全卸载旧包:

npm uninstall @material-ui/*

第四步:运行 codemod 处理破坏性变更

仓库迁移文档强调:绝大多数破坏性变更可以通过官方 codemod 自动改写。优先使用聚合了大部分转换器的 preset-safe,但它对同一目录只应运行一次

npx @mui/codemod@latest v5.0.0/preset-safe <path>

另有三个针对性 codemod 值得了解(它们的产物可反推出 v5 中两个重要的默认值变更):

  • variant-prop:为未显式指定 variant<TextField /><FormControl /><Select /> 补上 variant="standard"——因为默认值已从 v4 的 "standard" 改为 v5 的 "outlined"。如果你已经在主题里把 variant: 'outlined' 设为默认值,就不要再运行它;
  • link-underline-hover:为未指定 underline<Link /> 补上 underline="hover"——默认值已从 v4 的 "hover" 改为 v5 的 "always"。同理,若主题已把 underline: 'always' 设为默认,则无需运行。
npx @mui/codemod@latest v5.0.0/variant-prop <path>
npx @mui/codemod@latest v5.0.0/link-underline-hover <path>

第五步:处理 CSS 优先级与手动适配

codemod 无法覆盖全部变更,其余需要手动处理,例如 CSS 优先级调整:如果你习惯通过 import 普通 CSS 文件来覆盖组件样式,在 v5(Emotion 注入样式顺序变化后)需要提高选择器优先级。官方示例中,若想覆盖 Chip 的删除图标:

import './style.css';
import Chip from '@mui/material/Chip';

const ChipWithGreenIcon = () => (
  <Chip
    classes={{ deleteIcon: 'green' }}
    label="delete icon is green"
    onDelete={() => {}}
  />
);

单纯写 .green { color: green; } 无法命中,需要写成:

.MuiChip-root .green {
  color: green;
}

附:兼容性范围的显著变化

从仓库迁移文档可以确认,v5 还大幅收紧了浏览器与运行时的支持基线:默认 bundle 不再支持 IE 11;按 browserslist 查询 > 0.5%, last 2 versions, Firefox ESR, not dead, not IE 11, maintained node versions 推导,最低版本要求大致为 Node 12、Chrome 90、Edge 91、Firefox 78、Safari 14(macOS)/12.5(iOS)。如果你的产品仍必须支持 IE 11,需要在升级前另行评估 legacy bundle 方案。这些边界事实在动手升级前值得逐条核对。

结语与进一步阅读

v4 → v5 的迁移体量虽大,但官方通过"小步提交 + codemod 自动改写 + 渐进式样式迁移"的组合拳,已经把摩擦降到最低。升级的意义不仅在于拿到 React 18 支持与新样式引擎的性能收益,更在于提前站上 Emotion 化、sx 优先、类型完善、CSS variables 化这条后续所有大版本演进的主线上。

需要深入时,请在仓库内按如下顺序查阅:

登录后查看全文
热门项目推荐
相关项目推荐