您可以将自定义道具传递给 Material-UI v5 `styled()` 组件吗?

ben*_*neb 35 reactjs material-ui

例如,styled-components您可以执行以下操作:

const Div = styled.div`
  background: ${props => props.primary ? "palevioletred" : "white"};
  color: ${props => props.primary ? "white" : "palevioletred"};
`;

render(
  <section>
    <Div>Normal</Div>
    <Div primary>Primary</Div>
  </section>
);
Run Code Online (Sandbox Code Playgroud)

您能否使用 Material-UI v5 实用程序获得相同的结果,而不像styled() 文档styled中的示例那样向全局主题对象添加覆盖?

ben*_*neb 56

是的!

上述最基本的示例在 MUI v5 中如下所示:

const Div = styled("div")(({ primary }) => ({
  backgroundColor: primary ? "palevioletred" : "white",
  color: primary ? "white" : "palevioletred"
}));


render (
  <section>
    <Div>Normal</Div>
    <Div primary>Primary!</Div>
  <section>
);
Run Code Online (Sandbox Code Playgroud)

然而,正如React 文档所说:

如果您尝试使用 React 无法将其识别为合法 DOM 属性/属性的 prop 来渲染 DOM 元素,将会触发unknown-prop 警告。您应该确保您的 DOM 元素没有浮动的虚假 props。

因此,MUI 为我们提供了shouldForwardProp告诉 MUI 是否“应该将 prop 转发”到根节点的选项。使用该道具,上面的示例看起来像这样:

const Div = styled("div", {
  shouldForwardProp: (prop) => prop !== "primary"
})(({ primary }) => ({
  backgroundColor: primary ? "palevioletred" : "white",
  color: primary ? "white" : "palevioletred"
}));

render (
  <section>
    <Div>Normal</Div>
    <Div primary>Primary!</Div>
  <section>
);
Run Code Online (Sandbox Code Playgroud)

解释

styled函数的第二个参数是一个 options 对象,它接受的东西之一是shouldForwardProp,正如文档所说,“指示 prop 是否应该转发到组件”。因此,为了从控制台中删除未知的 prop 警告,我们告诉它不要将我们的自定义 prop 传递给带有shouldForwardProp: (prop) => prop !== "primary". 现在,我们在返回自定义样式的函数调用中解构这个 prop,并像使用任何其他函数一样在这些样式中使用它。

如果您也想在此处使用全局theme样式,只需将其与您的自定义道具一起解构即可,即({ primary, otherProp, thirdProp, theme }).

工作代码沙箱

MUI v5 styledAPI 文档

  • @HardikSolanki,你可以按照你喜欢的方式过滤它们,如果我喜欢做的不止一个`shouldForwardProp: (prop) =&gt; !["primary", "other prop", "etc"].includes(prop)` (2认同)

小智 25

这是一个完整工作的 MUI v5 TypeScript 示例,您可以在其中将自定义属性传递给样式化组件:

import React from 'react';
import { Button, styled, Typography } from '@mui/material';

const PREFIX = 'NimbusButton';
const classes = {
    root: `${PREFIX}-root`,
    button: `${PREFIX}-button`
};

interface RootProps {
    textColor?: 'primary' | 'secondary';
    buttonTextColor?: 'primary' | 'secondary';
}

const Root = styled('div', {
    shouldForwardProp: (prop) => prop !== 'textColor' && prop !== 'buttonTextColor',
    name: 'MyThemeComponent',
    slot: 'Root'
})<RootProps>(({ theme, textColor, buttonTextColor }) => ({
    [`& .${classes.root}`]: {
        color: textColor ? theme.palette.primary.main : theme.palette.secondary.main
    },
    [`& .${classes.button}`]: {
        color: buttonTextColor ? theme.palette.primary.main : theme.palette.secondary.main
    }
}));

type OwnProps = {
    textColor: 'primary' | 'secondary';
    buttonTextColor: 'primary' | 'secondary';
    text?: string;
    buttonText: string;
};

const CustomStyledButton: React.FC<OwnProps> = (props) => {
    const { textColor, buttonTextColor, text, buttonText } = props;
    return (
        <Root className={classes.root} textColor={textColor} buttonTextColor={buttonTextColor}>
            {text && <Typography variant={'body1'}>{text}</Typography>}
            <Button className={classes.button}>{buttonText}</Button>
        </Root>
    );
};

export default CustomStyledButton;
Run Code Online (Sandbox Code Playgroud)


mar*_*424 6

如果您使用 TypeScript,我会使用实用程序函数,因此我总是正确输入 prop 名称:

export const shouldForwardProp = <CustomProps extends Record<string, unknown>>(
  props: Array<keyof CustomProps>,
  prop: PropertyKey,
): boolean => !props.includes(prop as string);

const MyComponent = styled('div', {
  shouldForwardProp: (prop) => shouldForwardProp<MyComponentProps>(['isDisabled', 'bgColor'], prop),
})<MyComponentProps>(({ theme, isDisabled, size, bgColor }) => ({
...
Run Code Online (Sandbox Code Playgroud)