迁移到 Material-UI v5 时,如何处理条件类?

IT技术 reactjs material-ui
2021-05-16 03:49:06

官方迁移指南中,他们给出了以下示例,将代码从 JSS( makeStyles) 更改为新styled模式。

前:

const useStyles = makeStyles((theme) => ({
    background: theme.palette.primary.main,
}));

function Component() {
    const classes = useStyles();
    return <div className={classes.root} />
}

后:

const MyComponent = styled('div')(({ theme }) => 
    ({ background: theme.palette.primary.main }));

function App(props) {
    return (
        <ThemeProvider theme={theme}>
            <MyComponent {...props} />
        </ThemeProvider>
    );
}

这对于单个类来说很好,但是当代码有条件类时怎么办?

例如

<main className={classnames(content, open ? contentOpen : contentClosed)}>
    {/* content goes here */}
</main>

这里,contentcontentOpencontentClosed是从 返回的类useStyles,但是contentOpencontentClosed是基于 的值有条件地呈现open

使用新styled方法,我们生成组件而不是生成类名。有没有办法优雅地复制渲染而不诉诸三元表达式中的内容重复?

例如,我们希望做这样的事情:

function App(props) {
    return (
        <ThemeProvider theme={theme}>
            {open
            ? <MyOpenComponent {...props}>{/* content */}</MyOpenComponent>
            : <MyClosedComponent {...props}>{/* content */}</MyClosedComponent>
        </ThemeProvider>
    );
}
1个回答

有很多可能的方法来处理这个问题。使用的一种方法styled是利用 props 来做动态样式而不是尝试使用多个类。

下面是一个例子:

import React from "react";
import Button from "@mui/material/Button";
import { styled } from "@mui/material/styles";

const StyledDiv = styled("div")(({ open, theme }) => {
  const color = open
    ? theme.palette.primary.contrastText
    : theme.palette.secondary.contrastText;
  return {
    backgroundColor: open
      ? theme.palette.primary.main
      : theme.palette.secondary.main,
    color,
    padding: theme.spacing(0, 1),
    "& button": {
      color
    }
  };
});

export default function App() {
  const [open, setOpen] = React.useState(false);
  return (
    <StyledDiv open={open}>
      <h1>{open ? "Open" : "Closed"}</h1>
      <Button onClick={() => setOpen(!open)}>Toggle</Button>
    </StyledDiv>
  );
}

编辑替换 v5 中的多个 makeStyles 类

这是一个使用 TypeScript 的等效示例:

import * as React from "react";
import Button from "@mui/material/Button";
import { styled } from "@mui/material/styles";

const StyledDiv: React.ComponentType<{ open: boolean }> = styled("div")(
  ({ open, theme }) => {
    const color = open
      ? theme.palette.primary.contrastText
      : theme.palette.secondary.contrastText;
    return {
      backgroundColor: open
        ? theme.palette.primary.main
        : theme.palette.secondary.main,
      color,
      padding: theme.spacing(0, 1),
      "& button": {
        color
      }
    };
  }
);

export default function App() {
  const [open, setOpen] = React.useState(false);
  return (
    <StyledDiv open={open}>
      <h1>{open ? "Open" : "Closed"}</h1>
      <Button onClick={() => setOpen(!open)}>Toggle</Button>
    </StyledDiv>
  );
}

编辑替换 v5 中的多个 makeStyles 类

其他一些可能的方法:

  • 使用 Emotion 的cssprops和 Emotion 的功能来创作风格
  • 使用tss-react保留与makeStylesEmotion类似的语法但由 Emotion 支持(因此您不会在包中同时包含 Emotion 和 JSS,如果您利用makeStylesfrom就会出现这种情况@material-ui/styles