styled-components:使用额外的样式扩展现有组件

Posted

技术标签:

【中文标题】styled-components:使用额外的样式扩展现有组件【英文标题】:styled-components: Extend existing component with additional prop for styling 【发布时间】:2021-05-16 02:32:26 【问题描述】:

我正在使用 styled-components 覆盖现有组件的样式,在本例中是来自 Material ui 的 ToggleButton。但是我希望我的新组件有一个额外的属性 (hasMargin) 来控制样式:

import ToggleButton from "@material-ui/lab";
import styled, css from "styled-components";

const StyledToggleButton = styled(ToggleButton)< hasMargin?: boolean >`
  && 
    color: red;

    $props => props.hasMargin &&
      css`
          margin: 10px;
      `
   
`;

我的意图是StyledToggleButton 的行为与ToggleButton 完全相同,但具有红色,并且可以使用附加属性hasMargin 调用以打开边距css。我想这样称呼它:

    <StyledToggleButton
      value="" // ToggleButton prop
      size="small" // ToggleButton prop
      hasMargin=true // My prop from StyledToggleButton
    >
      click
    </StyledToggleButton>

但如果我这样做,在浏览器控制台中我会得到:

Warning: React does not recognize the `hasMargin` prop on a DOM element.

这是因为StyledToggleButton 似乎还将hasMargin 进一步传递给ToggleButtonToggleButton 当然不能也不应该处理它(将它传递给没有意义的DOM 元素)。重写我的代码的最佳方法是什么,所以hasMargin 仅由StyledToggleButton 处理?

我创建了一个codesandbox 来说明这个问题。谢谢!

【问题讨论】:

【参考方案1】:

这正是transient props 的用途。

您需要做的就是在 prop 前面加上 $styled-components 不会将 prop 传递给底层 DOM 元素。

// Note the $ prefix in the prop name             ?
const StyledToggleButton = styled(ToggleButton)< $hasMargin?: boolean >`
  && 
    color: red;

    // Just use the prop as normal
    $(props) =>
      props.$hasMargin &&
      css`
        margin: 10px;
      `
  
`;

<StyledToggleButton
  value=""
  size="small"
  /* Assign the prop as normal */
  $hasMargin=true
>
  click
</StyledToggleButton>;

这是您的updated Codesandbox link,错误消失了。

【讨论】:

太好了,谢谢!这正是我所需要的【参考方案2】:

用 span 包裹 ToggleButton 并从那里应用样式怎么样?

const StyledToggleButton = styled.span< hasMargin?: boolean >`
  margin: $props => props.hasMargin && '50px';
  
  button 
    color: red !important;
    
`

interface MyButtonProps extends ToggleButtonProps 
  hasMargin?: boolean;


function MyButton(props: MyButtonProps) 
  const  hasMargin, ...toggleButtonProps  = props;

  return (
    <StyledToggleButton hasMargin=hasMargin >
      <ToggleButton ...toggleButtonProps>
      props.children
      </ToggleButton>
    </StyledToggleButton>
  );


export default function App() 
  return (
    <div className="App">
      <MyButton value="">click</MyButton>

      <MyButton value="" size="small" hasMargin=true>
        click
      </MyButton>
    </div>
  );

【讨论】:

谢谢,这个简单的例子是一个选择。但我真的很想知道如何直接覆盖 ToggleButton。在我的实际项目中,不仅仅是保证金

以上是关于styled-components:使用额外的样式扩展现有组件的主要内容,如果未能解决你的问题,请参考以下文章

使用 styled-components 在组件/元素之间共享样式

使用 styled-components 设置 Router Link 的样式

是否可以在 Gatsby 中使用 styled-components 设置 StaticImage 的样式?

使用 styled-components 覆盖 material-ui 按钮样式

无法使用 styled-components 将样式应用于 React Native 中的自定义组件?

如何使用v4版本styled-components的全局样式?