跳转到内容

从JSS迁移(可选)

本指南解释了当从Material UI v4更新到v5时如何从JSS迁移到Emotion。

Material UI v5的迁移

  1. 快速入门
  2. 突破性变化第一部分:风格和主题
  3. 突破性变化第二部分:组件
  4. 从JSS迁移过来👈 你在这里
  5. 故障排除

从JSS迁移到Emotion

v5中最大的变化之一是将JSS替换为Emotion(或将styled-components作为替代)作为默认的样式解决方案。

请注意,你可以继续使用JSS为组件添加重写(例如makeStyles, withStyles),即使在迁移到v5之后。 然后,如果在任何时候你想转移到新的样式引擎,你可以逐步重构你的组件。

本文档回顾了从JSS迁移的所有必要步骤。

虽然你可以使用以下两个选项中的任何一个,但第一个被认为是最好的:

1. 使用styled或sx API

Codemod

我们提供了一个codemod来帮助将JSS样式迁移到styled的API,但这种方法增加了CSS的特殊性。

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

示例转换:

 import Typography from '@mui/material/Typography';
-import makeStyles from '@mui/styles/makeStyles';
+import { styled } from '@mui/material/styles';

-const useStyles = makeStyles((theme) => ({
-  root: {
-    display: 'flex',
-    alignItems: 'center',
-    backgroundColor: theme.palette.primary.main
-  },
-  cta: {
-    borderRadius: theme.shape.radius
-  },
-  content: {
-    color: theme.palette.common.white,
-    fontSize: 16,
-    lineHeight: 1.7
-  },
-}))
+const PREFIX = 'MyCard';
+const classes = {
+  root: `${PREFIX}-root`,
+  cta: `${PREFIX}-cta`,
+  content: `${PREFIX}-content`,
+}
+const Root = styled('div')(({ theme }) => ({
+  [`&.${classes.root}`]: {
+    display: 'flex',
+    alignItems: 'center',
+    backgroundColor: theme.palette.primary.main
+  },
+  [`& .${classes.cta}`]: {
+    borderRadius: theme.shape.radius
+  },
+  [`& .${classes.content}`]: {
+    color: theme.palette.common.white,
+    fontSize: 16,
+    lineHeight: 1.7
+  },
+}))

 export const MyCard = () => {
-  const classes = useStyles();
   return (
-    <div className={classes.root}>
+    <Root className={classes.root}>
       {/* The benefit of this approach is that the code inside Root stays the same. */}
       <Typography className={classes.content}>...</Typography>
       <Button className={classes.cta}>Go</Button>
-    </div>
+    </Root>
   )
 }

Manual

我们推荐sx API而不是styled用于创建响应式样式或覆盖次要的CSS。 Read more about sx here.

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

-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>
-      <Chip className={classes.chip} label="Chip" />
-    </div>
+    <Box sx={{ display: 'flex' }}>
+      <Chip label="Chip" sx={{ py: 1, px: 1.5, boxShadow: 1 }} />
+    </Box>
   );
 }

在某些情况下,你可能想在一个文件中创建多个styled的组件,而不是增加CSS的特殊性。

例如:

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

-const useStyles = makeStyles((theme) => ({
-  root: {
-    display: 'flex',
-    alignItems: 'center',
-    borderRadius: 20,
-    background: theme.palette.grey[50],
-  },
-  label: {
-    color: theme.palette.primary.main,
-  }
-}))
+const Root = styled('div')(({ theme }) => ({
+  display: 'flex',
+  alignItems: 'center',
+  borderRadius: 20,
+  background: theme.palette.grey[50],
+}))

+const Label = styled('span')(({ theme }) => ({
+  color: theme.palette.primary.main,
+}))

 function Status({ label }) {
-  const classes = useStyles();
   return (
-    <div className={classes.root}>
-      {icon}
-      <span className={classes.label}>{label}</span>
-    </div>
+    <Root>
+      {icon}
+      <Label>{label}</Label>
+    </Root>
   )
 }

2. Use tss-react

如果你使用styled-components作为底层样式引擎来代替@emotion,那么这个API将无法工作。

下面是一个使用 $ 语法、useStyles()参数、从classes道具中合并类(见doc)以及为样式表明确命名的综合例子

-import clsx from 'clsx';
-import { makeStyles, createStyles } from '@material-ui/core/styles';
+import { makeStyles } from 'tss-react/mui';

-const useStyles = makeStyles((theme) => createStyles<
-  'root' | 'small' | 'child', {color: 'primary' | 'secondary', padding: number}
->
-({
-  root: ({color, padding}) => ({
+const useStyles = makeStyles<{color: 'primary' | 'secondary', padding: number}, 'child' | 'small'>({name: 'App'})((theme, { color, padding }, classes) => ({
+  root: {
     padding: padding,
-    '&:hover $child': {
+    [`&:hover .${classes.child}`]: {
       backgroundColor: theme.palette[color].main,
     }
-  }),
+  },
   small: {},
   child: {
     border: '1px solid black',
     height: 50,
-    '&$small': {
+    [`&.${classes.small}`]: {
       height: 30
     }
   }
-}), {name: 'App'});
+}));

 function App({classes: classesProp}: {classes?: any}) {
-  const classes = useStyles({color: 'primary', padding: 30, classes: classesProp});
+  const { classes, cx } = useStyles({
+    color: 'primary',
+    padding: 30
+  }, {
+    props: {
+      classes: classesProp
+    }
+  });

   return (
     <div className={classes.root}>
       <div className={classes.child}>
         The Background take the primary theme color when the mouse hovers the parent.
       </div>
-      <div className={clsx(classes.child, classes.small)}>
+      <div className={cx(classes.child, classes.small)}>
         The Background take the primary theme color when the mouse hovers the parent.
         I am smaller than the other child.
       </div>
    </div>
  );
}

export default App;

在运行该代码后,在你的代码中搜索 "TODO jss-to-tss-react codemod",以找到该代码不能可靠地处理的情况。

除了那些有TODO注释的情况外,可能还有其他情况没有被codemod完全处理--特别是如果部分样式是由函数返回的。

如果埋在函数中的样式使用 $ 语法或useStyles参数,那么这些样式将不会被适当地迁移。

为了确保你的类名总是包括你的组件的实际名称,你可以将名称作为一个隐式命名的键来提供(name: { App }).

详情请见此tss-react文档

如果你解构了一个以上的项目,你可能会遇到类似这样的eslint警告。

不要犹豫,禁用eslint(prefer-const),在普通项目中是这样,在CRA中也是这样

withStyles()

tss-react also features a type-safe implementation of v4's withStyles().

-import Button from '@material-ui/core/Button';
+import Button from '@mui/material/Button';
-import withStyles from '@material-ui/styles/withStyles';
+import { withStyles } from 'tss-react/mui';

 const MyCustomButton = withStyles(
+  Button,
   (theme) => ({
     root: {
       minHeight: '30px',
     },
     textPrimary: {
       color: theme.palette.text.primary,
     },
     '@media (min-width: 960px)': {
       textPrimary: {
         fontWeight: 'bold',
       },
     },
   }),
-)(Button);
+);

 export default MyCustomButton;

Theme style overrides

全局主题覆盖是由TSS支持的。

按照Breaking changes doc相关部分的指示,为makeStyles

提供一个名字

在Material UI v5中,样式覆盖也接受回调

默认情况下,TSS只能够提供主题。 如果你想提供props和ownerState请参考这个文档

完成迁移

一旦你迁移了所有的样式,通过卸载软件包来移除不必要的@mui/styles

使用npm:

npm uninstall @mui/styles

用 yarn:

yarn remove @mui/styles