【问题标题】:How to properly use Styled() with MUI V5如何在 MUI V5 中正确使用 Styled()
【发布时间】:2021-12-19 23:02:42
【问题描述】:

我在尝试更大规模地使用 MUI Styled () 时遇到问题:有人可以看看我们在以前版本中使用的代码,并告诉我如何在 MUI V5 中复制它。

老办法:

const useStyles = makeStyles((theme) => ({
  root: {
    backgroundColor: "#fdfdff",
  },
  pageHeader: {
    padding: theme.spacing(4),
    display: "flex",
    marginBottom: theme.spacing,
  },
  pageIcon: {
    display: "inline-block",
    padding: theme.spacing(2),
    color: "#3c44b1",
  },
  pageTitle: {
    paddingLeft: theme.spacing(4),
    "& .MuiTypography-subtitle2": {
      opacity: "0.6",
    },
  },
}));
export default function PageHeader(props) {
  const classes = useStyles();
  const { title, subTitle, icon } = props;
  return (
    <Paper elevation={0} square className={classes.root}>
      <div className={classes.pageHeader}>
        <Card className={classes.pageIcon}>{icon}</Card>
        <div className={classes.pageTitle}>
          <Typography variant="h6" component="div">
            {title}
          </Typography>
          <Typography variant="subtitle2" component="div">
            {subTitle}
          </Typography>
        </div>
      </div>
    </Paper>
  );
}

我尝试在 MUI V5 中完成相同的操作无法正常工作。它会渲染,但看起来不一样,而且到处都是。

const rootStyle = styled("div")({
  backgroundColor: "#fdfdff",
});
const headerStyle = styled("div")(({ theme }) => ({
  padding: theme.spacing(4),
  display: "flex",
  marginBottom: theme.spacing,
}));
const iconStyle = styled("div")(({ theme }) => ({
  display: "inline-block",
  padding: theme.spacing(2),
  color: "#3c44b1",
}));
const titleStyle = styled("div")(({ theme }) => ({
  paddingLeft: theme.spacing(4),
  "& .MuiTypography-subtitle2": {
    opacity: "0.6",
  },
}));

export default function PageHeader(props) {
  const { title, subTitle, icon } = props;
  return (
    <rootStyle>
      <Paper elevation={0} square>
        <headerStyle>
          <iconStyle>
            <Card>{icon}</Card>
          </iconStyle>
          <titleStyle>
            <Typography variant="h6" component="div">
              {title}
            </Typography>
            <Typography variant="subtitle2" component="div">
              {subTitle}
            </Typography>
          </titleStyle>
        </headerStyle>
      </Paper>
    </rootStyle>
  );
}

我是 MUI 的新手,没有很多例子可以涵盖这一点。非常感谢您的帮助!

【问题讨论】:

  • This 应该可以解决您的问题。
  • 这里是新的间距方式的文档:mui.com/system/spacing
  • 我认为App.js中的部分是正确的,现在的问题是我们如何用新的方式替换makeStyles。我不只是追求间距;我在寻找如何在 v5 中使用主题
  • @Moe 你可以在 v5 中使用sx prop/styled。文档中有大量示例向您展示如何使用它们。
  • 我更新了问题;你能提供一个例子来说明如何使用样式复制我所拥有的

标签: javascript reactjs typescript material-ui


【解决方案1】:

下面是您的代码的 v5 版本,其外观与 v4 版本相同。我为道具添加了默认值只是为了演示。

您有两个主要问题:

  1. 您为样式添加了额外的 div 层,而不是为最初接收样式的元素设置样式(例如 PaperCard)。

  2. 您将 styled div 分配给以小写字母开头的变量名称,这导致它们被呈现为 DOM 标记而不是组件(因此样式将被完全忽略)。

来自https://reactjs.org/docs/components-and-props.html#rendering-a-component

React 将以小写字母开头的组件视为 DOM 标签。

import Paper from "@mui/material/Paper";
import Card from "@mui/material/Card";
import Typography from "@mui/material/Typography";
import { styled } from "@mui/material/styles";
import PersonIcon from "@mui/icons-material/Person";

const StyledPaper = styled(Paper)({
  backgroundColor: "#fdfdff"
});
const HeaderDiv = styled("div")(({ theme }) => ({
  padding: theme.spacing(4),
  display: "flex",
  marginBottom: theme.spacing
}));
const StyledCard = styled(Card)(({ theme }) => ({
  display: "inline-block",
  padding: theme.spacing(2),
  color: "#3c44b1"
}));
const TitleDiv = styled("div")(({ theme }) => ({
  paddingLeft: theme.spacing(4),
  "& .MuiTypography-subtitle2": {
    opacity: "0.6"
  }
}));

export default function PageHeader(props) {
  const {
    title = "Title",
    subTitle = "sub-title",
    icon = <PersonIcon />
  } = props;
  return (
    <StyledPaper elevation={0} square>
      <HeaderDiv>
        <StyledCard>{icon}</StyledCard>
        <TitleDiv>
          <Typography variant="h6" component="div">
            {title}
          </Typography>
          <Typography variant="subtitle2" component="div">
            {subTitle}
          </Typography>
        </TitleDiv>
      </HeaderDiv>
    </StyledPaper>
  );
}

将 v4 代码转换为 v5 的另一种(更简洁)方法是使用 sx 属性:

import Paper from "@mui/material/Paper";
import Card from "@mui/material/Card";
import Typography from "@mui/material/Typography";
import PersonIcon from "@mui/icons-material/Person";
import Box from "@mui/material/Box";

export default function PageHeader(props) {
  const {
    title = "Title",
    subTitle = "sub-title",
    icon = <PersonIcon />
  } = props;
  return (
    <Paper elevation={0} square sx={{ bgcolor: "#fdfdff" }}>
      <Box sx={{ p: 4, display: "flex", mb: 1 }}>
        <Card sx={{ display: "inline-block", p: 2, color: "#3c44b1" }}>
          {icon}
        </Card>
        <Box sx={{ pl: 4, "& .MuiTypography-subtitle2": { opacity: 0.6 } }}>
          <Typography variant="h6" component="div">
            {title}
          </Typography>
          <Typography variant="subtitle2" component="div">
            {subTitle}
          </Typography>
        </Box>
      </Box>
    </Paper>
  );
}

这里还有一个使用单个 styled 调用的选项,但我认为这比其他选项更易维护:

import Paper from "@mui/material/Paper";
import Card from "@mui/material/Card";
import Typography from "@mui/material/Typography";
import { styled } from "@mui/material/styles";
import PersonIcon from "@mui/icons-material/Person";

const StyledPaper = styled(Paper)(({ theme }) => ({
  backgroundColor: "#fdfdff",
  "& > div": {
    padding: theme.spacing(4),
    display: "flex",
    marginBottom: theme.spacing(1),
    "& .MuiCard-root": {
      display: "inline-block",
      padding: theme.spacing(2),
      color: "#3c44b1"
    },
    "& > div": {
      paddingLeft: theme.spacing(4),
      "& .MuiTypography-subtitle2": {
        opacity: "0.6"
      }
    }
  }
}));

export default function PageHeader(props) {
  const {
    title = "Title",
    subTitle = "sub-title",
    icon = <PersonIcon />
  } = props;
  return (
    <StyledPaper elevation={0} square>
      <div>
        <Card>{icon}</Card>
        <div>
          <Typography variant="h6" component="div">
            {title}
          </Typography>
          <Typography variant="subtitle2" component="div">
            {subTitle}
          </Typography>
        </div>
      </div>
    </StyledPaper>
  );
}

【讨论】:

  • 感谢您的详细解释:如果可以的话,还有一个问题,有没有办法像我们之前使用 useStyles (旧方式)一样整合样式化组件。在每个 const 组件中传递主题是重复的。有办法避免吗?
  • @Moe 没有直接的方法可以避免为每个 styled 调用传递主题,除非您通过单个 styled 调用完成所有样式设置,然后定位样式中的后代元素,但我认为这会导致更复杂的样式更难以维护。一种替代方法是使用sx 属性而不是styled——我已经添加了一个示例。
  • 再次感谢您!我尝试了单一样式,但无法调用该组件。所以我要求知道正确和最好的方法。总而言之,要么将它们分解成小组件,要么使用 sx 来设置样式。
  • @Moe 我添加了一个额外的示例,展示了使用单个 styled 调用的一种方法。没有真正的“正确和最佳方式”来设置样式 - 根据您的场景的具体情况,有许多选项具有不同的权衡。
  • 非常感谢,我想社区也会感谢您的回答。非常感谢您抽出宝贵时间帮助我们。
猜你喜欢
  • 2021-11-19
  • 2021-11-17
  • 2022-10-24
  • 2022-12-16
  • 2021-12-08
  • 1970-01-01
  • 2021-12-09
  • 2021-12-11
相关资源
最近更新 更多