React 无法识别传递给 Material UI 中样式化组件的道具

Posted

技术标签:

【中文标题】React 无法识别传递给 Material UI 中样式化组件的道具【英文标题】:React does not recognize the prop passed to a styled-component within 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; 不是错字,仅供参考:typescriptlang.org/docs/handbook/release-notes/… 谢谢 - 但是,仍然 - 在这里使用它有什么意义?就像你使用$( textColor ) =&gt; textColor 【参考方案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>

【讨论】:

以上是关于React 无法识别传递给 Material UI 中样式化组件的道具的主要内容,如果未能解决你的问题,请参考以下文章

React Material-UI无法调整表格大小

TS 表达式生成的联合类型过于复杂,无法用 Material-UI 和 @react-three/fiber 表示

如何使 Material-UI Dialog 在 React 中工作

material-ui 组件|日期选择器 |没有数据传递给 onChange

无法让 material-ui datepicker 工作

无法从 Material UI DatePicker 获取值