从JSS迁移(可选)
本指南解释了当从Material UI v4更新到v5时如何从JSS迁移到Emotion。
Material UI v5的迁移
- 快速入门
- 突破性变化第一部分:风格和主题
- 突破性变化第二部分:组件
- 从JSS迁移过来👈 你在这里
- 故障排除
从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