從 JSS 遷移 (選用)
本指南說明在從 Material UI v4 更新至 v5 時,如何從 JSS 遷移至 Emotion。
Material UI v5 遷移
- 開始使用
- 重大變更第一部分:樣式與主題
- 重大變更第二部分:元件
- 從 JSS 遷移 👈 您在這裡
- 疑難排解
從 JSS 遷移至 Emotion
v5 中最大的變更之一是以 Emotion (或 styled-components 作為替代方案) 取代 JSS 作為預設的樣式解決方案。
請注意,即使遷移至 v5 之後,您仍然可以繼續使用 JSS 來為元件新增覆寫 (例如 makeStyles
、withStyles
)。然後,如果您在任何時候想要轉換到新的樣式引擎,您可以逐步重構您的元件。
本文檔回顧了從 JSS 遷移所需的所有步驟。
雖然您可以使用以下兩個選項中的任何一個,但第一個選項被認為更佳
1. 使用 styled 或 sx API
Codemod
我們提供一個 codemod,以協助將 JSS 樣式遷移至 styled
API,但此方法會增加 CSS 的特異性。
npx @mui/codemod@latest 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>
)
}
手動
我們建議使用 sx
API 而不是 styled
來建立響應式樣式或覆寫次要 CSS。在此處閱讀更多關於 sx
的資訊。
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}>
- <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. 使用 tss-react
此 API 與 JSS makeStyles
類似,但在底層,它使用 @emotion/react
。與 v4 的 makeStyles
相比,它還具有更好的 TypeScript 支援。
為了使用它,您需要將其新增至專案的依賴項
使用 npm
npm install tss-react
使用 yarn
yarn add tss-react
Codemod
我們提供一個 codemod,以協助將 JSS 樣式遷移至 tss-react
API。
npx @mui/codemod@latest v5.0.0/jss-to-tss-react <path>
範例轉換
import * as React from 'react';
-import makeStyles from '@material-ui/styles/makeStyles';
+import { makeStyles } from 'tss-react/mui';
import Button from '@mui/material/Button';
import Link from '@mui/material/Link';
-const useStyles = makeStyles((theme) => {
+const useStyles = makeStyles()((theme) => {
return {
root: {
color: theme.palette.primary.main,
},
apply: {
marginRight: theme.spacing(2),
},
};
});
function Apply() {
- const classes = useStyles();
+ const { classes } = useStyles();
return (
<div className={classes.root}>
<Button component={Link} to="https://support.mui.com" className={classes.apply}>
Apply now
</Button>
</div>
);
}
export default Apply;
如果您使用 $
語法和 clsx
來組合多個 CSS 類別,則轉換將如下所示
import * as React from 'react';
-import { makeStyles } from '@material-ui/core/styles';
-import clsx from 'clsx';
+import { makeStyles } from 'tss-react/mui';
-const useStyles = makeStyles((theme) => ({
+const useStyles = makeStyles<void, 'child' | 'small'>()((theme, _params, classes) => ({
parent: {
padding: 30,
- '&:hover $child': {
+ [`&:hover .${classes.child}`]: {
backgroundColor: 'red',
},
},
small: {},
child: {
backgroundColor: 'blue',
height: 50,
- '&$small': {
+ [`&.${classes.small}`]: {
backgroundColor: 'lightblue',
height: 30
}
},
}));
function App() {
- const classes = useStyles();
+ const { classes, cx } = useStyles();
return (
<div className={classes.parent}>
<div className={classes.child}>
Background turns red when the mouse hovers over the parent.
</div>
- <div className={clsx(classes.child, classes.small)}>
+ <div className={cx(classes.child, classes.small)}>
Background turns red when the mouse hovers over the parent.
I am smaller than the other child.
</div>
</div>
);
}
export default App;
以下是一個全面的範例,使用了 $
語法、useStyles()
參數、從 classes
prop 合併類別 (請參閱文件) 以及 樣式表的明確名稱 (對於偵錯和主題樣式覆寫很有用)。
-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;
執行 codemod 後,搜尋您的程式碼中是否有 "TODO jss-to-tss-react codemod",以尋找 codemod 無法可靠處理的情況。
可能還有其他超出那些帶有 TODO 註解的情況未被 codemod 完全處理—特別是當樣式的部分是由函數傳回時。
如果函數中埋藏的樣式使用 $
語法或 useStyles
參數,則這些樣式將不會被適當地遷移。
為了確保您的類別名稱始終包含元件的實際名稱,您可以提供 name
作為隱式命名的鍵 (name: { App }
)。
請參閱 此 tss-react 文件 以取得詳細資訊。
如果您解構多個項目,您可能會遇到 eslint 警告 像這樣。
請隨時停用 eslint(prefer-const)
,像這樣在常規專案中,或 像這樣在 CRA 中。
withStyles()
tss-react
還具有 類型安全實作 的 v4 的 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;
主題樣式覆寫
TSS 開箱即用支援全域主題覆寫。
請按照重大變更文件中相關章節的說明進行操作,並為 makeStyles
提供 name
。
在 Material UI v5 中,樣式覆寫也接受回呼函數。
預設情況下,TSS 只能提供主題。如果您想要提供 props 和 ownerState
,請參考此文件。
完成遷移
遷移所有樣式後,透過解除安裝套件來移除不必要的 @mui/styles
。
使用 npm
npm uninstall @mui/styles
使用 yarn
yarn remove @mui/styles