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

And*_*rei 2 reactjs material-ui

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

前:

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

function Component() {
    const classes = useStyles();
    return <div className={classes.root} />
}
Run Code Online (Sandbox Code Playgroud)

后:

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

function App(props) {
    return (
        <ThemeProvider theme={theme}>
            <MyComponent {...props} />
        </ThemeProvider>
    );
}
Run Code Online (Sandbox Code Playgroud)

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

例如

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

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

使用新styled方法,我们不再生成类名,而是生成组件。有没有一种方法可以优雅地复制渲染,而无需在三元表达式中进行内容重复?

例如我们不想做类似的事情:

function App(props) {
    return (
        <ThemeProvider theme={theme}>
            {open
            ? <MyOpenComponent {...props}>{/* content */}</MyOpenComponent>
            : <MyClosedComponent {...props}>{/* content */}</MyClosedComponent>
        </ThemeProvider>
    );
}
Run Code Online (Sandbox Code Playgroud)

Rya*_*ell 7

有很多可能的方法来处理这个问题。一种使用方法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>
  );
}
Run Code Online (Sandbox Code Playgroud)

编辑替换 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>
  );
}
Run Code Online (Sandbox Code Playgroud)

编辑替换 v5 中的多个 makeStyles 类

其他一些可能的方法:

  • 使用 Emotion 的cssprop 和 Emotion 的功能来构建风格
  • 使用tss-react保留与 Emotion 类似的语法,makeStyles但由 Emotion 支持(因此您不会像利用makeStylesfrom那样在捆绑包中同时包含 Emotion 和 JSS @material-ui/styles)。这是我迁移到 v5 时采取的路线,作为迁移的一部分,我创建了一个用于将 JSS 迁移到 tss-react的codemodmakeStylesmakeStyles