首页
/ MUI System v7 到 v9 升级完全指南:废弃 system 属性迁入 sx 与 Grid 方向限制的实战落地

MUI System v7 到 v9 升级完全指南:废弃 system 属性迁入 sx 与 Grid 方向限制的实战落地

2026-09-06 18:15:45作者:邬祺芯Juliet

<输出文章结束标记仅为占位,正文见下>

导读

本文以 MUI System v7 升级到 v9 官方迁移文档为骨架,系统梳理本次大版本中最影响日常写码的两类破坏性变更:从 BoxGridStack 等组件上移除废弃的 system 快捷属性(统一收敛到 sx),以及 Grid 不再支持 direction="column"(改由 Stack 承担纵向布局)。读完你会拿到可直接执行的 codemod 迁移命令、逐行的改码对照,以及本仓库 codemod 源码与 Grid 类型定义层面的底层证据,能够安全地把项目从 v7 迁到 v9。

说明:本文聚焦 MUI System(@mui/system)。如果你的项目同时使用了 Material UI 组件库,其 v9 变更覆盖面更广,可另见 Material UI v7 到 v9 升级指南

为什么值得升级到 MUI System v9

官方文档在 upgrade-to-v9.md 中给出了两个核心理由,它们共同指向"更少 API 面、更一致行为"的设计方向。

更一致的样式 API:system props 退场,sx 统一收口

v9 从组件上移除了那些已被废弃多年的 system 快捷属性,强制把样式表达收敛到 sx prop 上。收益是三层:

  • API 表面积更小:布局类组件不再同时暴露 mtpdisplay 等几十个透传属性;
  • 行为更一致:不同组件之间不再存在"有的属性走了样式系统、有的被透传给了 DOM"的分裂;
  • 避免属性冲突:这正是文档特别点出的一点——此前像 color 这类属性可能被组件"截胡"消费,而不是透传给通过 component prop 渲染的底层元素。

更清晰的布局原语:Grid 管二维,Stack 管纵向

v9 让 Grid 回归"把二维布局切分为列"的本职,不再被用作纵向堆叠容器;纵向布局统一交给 Stack。职责边界越清晰,API 就越容易推理,也越贴合各自的设计意图。这一方向在仓库中同样有明确呈现,见下文 Grid 方向限制

升级前的整体判断与版本配套

v9 是一次新的主版本(major release),必然伴随公开 API 的破坏性变更。进行升级时请注意:

  • 你需要把 @mui/system 及其配套依赖提升到 9.0.0 及兼容版本;
  • 若同仓使用 Material UI,@mui/icons-material@mui/material-nextjs@mui/styled-engine@mui/styled-engine-sc@mui/utils 等也需同步到 9.0.0@mui/lab 升级到最新的 v9 beta),版本清单见 Material UI v9 升级文档
  • 升级前建议先提交干净的基线,逐条应用下文变更并跑一遍类型检查(tsc)与测试,便于定位回归。

Breaking change 一:废弃的 system 属性被移除

受影响组件

官方文档明确点名了三个组件:BoxGridStack。需要说明的是,文档示例使用的是 @mui/system 下的这几个组件,而仓库中 codemod 的默认组件清单实际覆盖得更广。

查看 codemod 源码 removeSystemProps.js 中的 components 常量,处理对象还包括 Material UI 中继承/复用了 system 能力的 TypographyLinkGrid2DialogContentTextTimelineContentTimelineOppositeContent。也就是说:凡是在这些组件上直接写 mtpcolor 等快捷属性的代码,都属于本次清扫范围。

推荐的自动化迁移命令

文档给出的迁移方式是用官方 codemod 一次性改写,命令如下:

npx @mui/codemod@latest v9.0.0/system-props <path/to/folder>

其中 <path/to/folder> 替换为你希望递归处理的源码目录(例如 src/)。codemod 的实现在仓库中的位置是 packages/mui-codemod/src/v9.0.0/system-props/removeSystemProps.js

手工迁移的代码对照

文档给出了逐组件的最小 diff,务必完整核对:

-<Box mt={2} color="primary.main" />
+<Box sx={{ mt: 2, color: 'primary.main' }} />

-<Grid mt={2} mr={1} />
+<Grid sx={{ mt: 2, mr: 1 }} />

-<Stack mt={2} alignItems="center" />
+<Stack sx={{ mt: 2, alignItems: 'center' }} />

迁移的同时,也顺带修复了文档提到的历史问题:像 color 这样的属性此前可能被组件自身消费掉,而现在它作为 sx 内容被正确应用到 component prop 渲染出的底层元素上。

深入 codemod:它到底改了什么

从源码看,removeSystemProps 的转换策略非常值得理解,因为它决定了你 review diff 时该看什么:

  1. 属性白名单来自 defaultSxConfig。源码第一行注释写明其属性集合取自 packages/mui-system/src/styleFunctionSx 下的 defaultSxConfig.js,涵盖 borders(borderborderRadiusborderColor…)、spacing(p/px/pym/mx/my 及 margin/padding 全拼)、display(displayoverflowwhiteSpace…)、flexbox、grid(gapgridTemplateColumns…)、positions(positionzIndex…)、shadows(boxShadow)、sizing(widthheight…)、typography(fontSizefontWeight…)等全部可被 sx 消化的键。
  2. JSX 属性搬移 + 合并。它只把属于白名单、且当前组件受影响的 JSX 属性从元素上剥离并收进新生成的 sx 对象;若元素原本已有 sx(对象、数组或标识符形式),会按类型智能合并,已有 sx 永远保留优先级。
  3. 处理展开属性(spread)。当组件存在 {...restProps} 这类展开时,codemod 会追加一个基于 restProps.sx 的展开合并逻辑(配合 Array.isArray 判断),尽可能避免丢失运行期传入的样式。
  4. 特殊组件有例外规则。对 Typography 及其派生的 DialogContentTextTimelineContentTimelineOppositeContentcolor 只有在取 inherit、含 .(主题色如 primary.main)、divider#hex 或函数调用时才搬进 sx,其余取值会被保留在组件 prop 上以免误伤文本默认色逻辑;Link 类似,但 color="inherit" 会被保留,因为它在 Link 上还承担着控制下划线行为的语义。
  5. 仅处理 @mui 开头的导入来源,避免误伤其它库;同时跳过 .json.d.ts 文件。

这些行为都有配套测试锁定,见 removeSystemProps.test.js:测试覆盖了标准转换、幂等性(对转换结果再跑一次应保持输出不变)、packageName 选项(支持把 codemod 用于内部封装的 @acme/ui 这类自定义包)以及 jsx 选项(显式声明自动引入、无法通过 import 识别来源的组件名,如 Box,Typography,Stack,Link 或任意自定义名)。

对使用该 codemod 的实践启示:

  • 推荐先对目录跑一次,随后用 git diff 逐块核对,尤其留意 Typography/Linkcolor 是否被正确处理;
  • 若你的代码把组件从自定义封装里再导出、import 分析识别不到,可通过 --jsx 类选项补充组件名(详见 packages/mui-codemod/README.md 对 v9.0.0/system-props 的说明);
  • codemod 是幂等的,可以在 review 后放心重跑同一目录而不必担心二次污染。

Breaking change 二:Grid 不再支持 direction="column"

变更说明

Grid 组件不再接受 direction="column"direction="column-reverse"。文档给出的理由是:Grid 的定位是把布局切分为(columns)的二维网格,而不是做纵向堆叠;纵向布局应当使用 Stack

这一点在源码中有双重印证:

  • 类型层面,GridProps.tsGridDirection 已被收窄为 type GridDirection = 'row' | 'row-reverse'
  • 组件注释层面,Grid.tsxGridProps.ts 的 JSDoc 均明确写着:只有 rowrow-reverse 被支持,column/column-reverse 不受支持,因为 Grid 是被设计来把布局细分为而非行的。

Material UI 侧的 v9 文档补充了一个重要背景:这两个取值"在此前版本中实际上就并未被真正支持",本次只是把它们从 TypeScript 类型与 prop 校验中正式剔除。如果你仍需要横向的列细分,请继续使用默认的 direction="row"direction="row-reverse"

迁移示例:纵向布局改用 Stack

文档给出了完整的前后对照:

-import Grid from '@mui/system/Grid';
+import Stack from '@mui/system/Stack';

-<Grid container direction="column" spacing={2}>
-  <Grid>First item</Grid>
-  <Grid>Second item</Grid>
-</Grid>
+<Stack spacing={2}>
+  <div>First item</div>
+  <div>Second item</div>
+</Stack>

要点拆解:

  • Grid container direction="column" spacing={2} 整体替换为一个 Stack spacing={2}——spacing 语义在 Stack 上原样保留;
  • 原先每个 Grid 子项(即逻辑上的一"行")替换为普通元素(文档用 <div>);如果子项内部还需要做水平细分,可以继续在子项内嵌套 Grid,即"外层 Stack 负责纵向、内层 Grid 负责横向"的组合(Material UI 侧文档称之为"inside a Grid item when needed");
  • 若你是从 @mui/system 之外的入口(如 @mui/material/Grid)导入,同样适用——纵向堆叠交给 Stack(对应入口为 @mui/material/Stack)。

一份可对照执行的升级清单

把上述两类变更落到项目里,推荐按如下顺序操作:

  1. 锁版本:在 package.json 中把 @mui/system(及配套依赖)提升到 v9 兼容版本,重新安装依赖。

  2. 跑 codemod 清扫 system 属性

    npx @mui/codemod@latest v9.0.0/system-props src/
    

    若还使用了 TypographyLink 等派生组件,确认它们也在处理范围内;自定义封装场景参考 README 补充选项。

  3. 处理 Grid 方向:全局搜索 direction="column"(含 column-reverse),逐个按上文 diff 改写为 Stack,必要时在 Stack 子项里保留 Grid 做水平列细分。

  4. 检查颜色与透传:重点 review 原先依赖 color 等属性被组件"消费"的写法,确认迁移后样式经 sx 落到了 component 指定的元素上。

  5. 验证:运行类型检查与组件测试。由于 codemod 输出可预测且幂等,git diff 应该清晰可审;本仓库的 codemod 测试(幂等、自定义包名、jsx 组件名等用例)可作为你验收改写的参考口径。

参考与进一步阅读

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