【问题标题】:React does not recognize the prop passed to a styled-component within Material UIReact 无法识别传递给 Material UI 中样式化组件的道具
【发布时间】:2020-08-12 18:10:19
【问题描述】:

样式化组件:

import { Typography } from '@material-ui/core';

const Text = styled(Typography)<TextProps>`
  margin-bottom: 10px;
  color: ${({ textColor }) => textColor ?? textColor};
  font-size: ${({ textSize }) => (textSize ? textSize + 'px' : '16px')};
`;

在组件内部使用:

<GlobalStyled.Text textColor="green" textSize="20">test</GlobalStyled.Text>

“警告:React 无法识别 DOM 元素上的 textColor 属性。如果您故意希望它作为自定义属性出现在 DOM 中,请将其拼写为小写 textcolor。如果您不小心从父组件,将其从 DOM 元素中移除。”

props 被传递给 Typography 组件本身,而不仅仅是 styled-component,如何解决这个问题?

更新

5.1.0 发布的样式化组件:https://github.com/styled-components/styled-components/releases/tag/v5.1.0

现在有新的瞬态道具,通过道具过滤解决了这个问题。您可以在道具名称前使用$propsName,这是一个美元符号,它将仅传递给样式组件!

【问题讨论】:

  • 错字 - color: ${({ textColor }) =&gt; textColor &amp;&amp; textColor}; 甚至只是 color: ${({ textColor }) =&gt; textColor};
  • 谢谢 - 但是,仍然 - 在这里使用它有什么意义?就像你使用${({ textColor }) =&gt; textColor}

标签: javascript reactjs typescript material-ui styled-components


【解决方案1】:

你需要得到你不想要的道具,剥掉它们,然后把里面的其余部分传递出去:

const Text = styled( ({textColor, textSize, ...rest}) => <Typography {...rest}/>)<TextProps>`
  margin-bottom: 10px;
  color: ${({ textColor }) => textColor ?? textColor};
  font-size: ${({ textSize }) => (textSize ? textSize + "px" : "16px")};
`;

这是一个工作示例(没有 TextProps 类型,但它应该可以工作):https://codesandbox.io/s/mui-styled-component-removed-props-rfdjx?file=/src/App.js

这是一个使用 Typescript 的工作示例:

import * as React from "react";

import Typography, {TypographyProps} from '@material-ui/core/Typography';
import {StylesProvider} from '@material-ui/core/styles';
import styled from 'styled-components';

interface TextProps extends TypographyProps {
  textColor: string,
  textSize: number
}

const TypographyWrapper = React.forwardRef<HTMLSpanElement, TextProps>(
  function TypographyWrapper({textColor, textSize, ...other}: TextProps, ref) {
    return <Typography {...other} ref={ref}/>
  }
);
const Text = styled(TypographyWrapper)<TextProps>`
  margin-bottom: 10px;
  color: ${({ textColor }: TextProps) => textColor ?? textColor};
  font-size: ${({ textSize }: TextProps) => (textSize ? textSize + 'px' : '16px')};
`;

export default function App() {
  return <StylesProvider injectFirst>
    <Text textColor="green">Hello World!</Text>
    <Text textColor="red" textSize={30}>Hello World!</Text>
  </StylesProvider>;
}

【讨论】:

  • 你知道现在如何正确输入道具吗?我试过{ textColor, textSize, ...rest }: TextProps,但由于孩子而引发错误:“类型'{孩子:字符串;}'与类型没有共同的属性”
  • @AlexanderKim 我在这个答案中添加了一个 Typescript 示例。
  • 谢谢,我刚刚阅读了 styled-components 5.1.0 发行说明,他们已经实现了瞬态道具:github.com/styled-components/styled-components/releases/tag/…,我刚刚使用了瞬态道具$propsName,它就起作用了!
  • @RyanCogswell,仅仅通过自定义 SC 道具看起来工作量太大了,哈哈,我很高兴他们终于推出了这些临时道具。
  • @AlexanderKim 是的,瞬态道具听起来是一个更好的解决方案。
【解决方案2】:

使用version 5.1.0,styled-components 支持瞬态道具。瞬态道具不会传递给组件(即仅在样式中使用),并通过以 $ 开头的道具名称来指示。这允许以更简单的方式管理此场景,不再需要包装器组件来删除额外的道具(如 Dekel 的回答)。

import * as React from "react";

import Typography, { TypographyProps } from "@material-ui/core/Typography";
import { StylesProvider } from "@material-ui/core/styles";
import styled from "styled-components";

interface TextProps extends TypographyProps {
  $textColor?: string;
  $textSize?: number;
}

const Text: React.FunctionComponent<TextProps> = styled(Typography)`
  margin-bottom: 10px;
  color: ${({ $textColor }: TextProps) => $textColor};
  font-size: ${({ $textSize }: TextProps) =>
    $textSize ? $textSize + "px" : "16px"};
`;

export default function App() {
  return (
    <StylesProvider injectFirst>
      <Text $textColor="green">Hello World!</Text>
      <Text $textColor="red" $textSize={30}>
        Hello World!
      </Text>
    </StylesProvider>
  );
}

【讨论】:

    【解决方案3】:

    使用样式组件中的“瞬态道具”

    https://styled-components.com/releases

    样式化组件

    import styled from "styled-components";
    import Typography, { TypographyProps } from "@material-ui/core/Typography";
        
    interface TextProps {
        $textColor?: string;
        $textSize?: number;
    }
    
    export default styled(Typography)<TypographyProps & TextProps>`
        margin-bottom: 10px;
        color: ${(props) => props?.$textColor || 'black'};
        font-size: ${(props) => props?.$textSize ? props?.$textSize +'px' : '16px'} !important;
    `;
    

    使用

    import React from "react";
    import { render } from "react-dom";
    import Text from "./components/Text";
    
    function App() {
      return (
        <>
          <Text $textColor="blue" $textSize="50" align="center">
            text ok
          </Text>
        </>
      );
    }
    
    const rootElement = document.getElementById("root");
    render(<App />, rootElement);
    

    https://codesandbox.io/s/react-typescript-transient-styledcomponent-example-eb9uf?expanddevtools=1&fontsize=14&hidenavigation=1&theme=dark

    <iframe src="https://codesandbox.io/embed/react-typescript-transient-styledcomponent-example-eb9uf?expanddevtools=1&fontsize=14&hidenavigation=1&theme=dark" style="width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;" title="react-typescript-transient-styledcomponent-example"
      allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking" sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"></iframe>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-11-24
      • 2021-09-11
      • 2020-10-28
      • 2020-12-21
      • 2021-05-28
      • 1970-01-01
      • 1970-01-01
      • 2017-05-15
      相关资源
      最近更新 更多