如何在不将props传递给底层DOM元素的情况下扩展样式化组件?

时间:2018-04-14 17:31:32

标签: reactjs styled-components

我有一个扩展第三方组件的样式组件:

import Resizable from 're-resizable';
...
const ResizableSC = styled(Resizable)``;
export const StyledPaneContainer = ResizableSC.extend`
    flex: 0 0 ${(props) => props.someProp}px;
`;


const PaneContainer = ({ children, someProp }) => (
    <StyledPaneContainer
        someProp={someProp}
    >
        {children}
    </StyledPaneContainer>
);

export default PaneContainer;

这导致浏览器控制台出现以下错误:

  

警告:React无法识别DOM上的someProp道具   元件。如果您有意希望它作为自定义出现在DOM中   属性,拼写为小写someProp。如果你   意外地从父组件传递它,从DOM中删除它   元件

因此,我将道具更改为data-*属性名称:

import Resizable from 're-resizable';
...
const ResizableSC = styled(Resizable)``;
export const StyledPaneContainer = ResizableSC.extend`
    flex: 0 0 ${(props) => props['data-s']}px;
`;


const PaneContainer = ({ children, someProp }) => (
    <StyledPaneContainer
        data-s={someProp}
    >
        {children}
    </StyledPaneContainer>
);

export default PaneContainer;

这很有效,但我想知道是否有一种原生方式在样式化组件中使用道具而不将它们传递给DOM元素(?)

4 个答案:

答案 0 :(得分:20)

2020更新:使用瞬态道具

通过release 5.1.0,您可以使用瞬态道具。这样,您不需要额外的包装程序,即减少了不必要的代码:

临时道具是一种传递道具的新模式,道具仅由样式化组件显式使用,而无意传递给更深的组件层。使用方法如下:

const Comp = styled.div`
  color: ${props => props.$fg || 'black'};
`;

render(<Comp $fg="red">I'm red!</Comp>);

请注意道具上的美元符号($)前缀;这标记为暂时的,样式化组件不知道将其添加到呈现的DOM元素中,也不将其进一步传递到组件层次结构中。

新答案应为:

样式化的组件:

const ResizableSC = styled(Resizable)``;
export const StyledPaneContainer = ResizableSC.extend`
    flex: 0 0 ${(props) => props.$someProp}px;
`;

父组件:

const PaneContainer = ({ children, someProp }) => (
    <StyledPaneContainer
        $someProp={someProp}  // '$' signals the transient prop        
    >
        {children}
    </StyledPaneContainer>
);

答案 1 :(得分:9)

根据vdanchenkov this styled-components github issue的建议,您可以对道具进行细分,并仅将相关的道具传递给Resizable

const ResizableSC = styled(({ someProp, ...rest }) => <Resizable {...rest} />)`
    flex: 0 0 ${(props) => props.someProp}px;
`;

答案 2 :(得分:2)

对于那些由于SC和react-router的Link问题而降落在这里的人(如我):

const StyledLink = styled(({ isCurrent, ...rest }) => <Link {...rest} />)(
  ({ isCurrent }) => ({
    borderBottomColor: isCurrent ? 'green' : 'transparent',
  }),
)

答案 3 :(得分:-1)

您可以尝试 defaultProps

import Resizable from 're-resizable';
import PropTypes from 'prop-types';
...
const ResizableSC = styled(Resizable)``;
export const StyledPaneContainer = ResizableSC.extend`
    flex: 0 0 ${(props) => props.someProp}px;
`;

StyledPaneContainer.defaultProps = { someProp: 1 }

const PaneContainer = ({ children }) => (
    <StyledPaneContainer>
        {children}
    </StyledPaneContainer>
);

export default PaneContainer;

我们也可以使用' attrs '传递道具。这有助于附加额外的道具(示例取自样式组件官方文档):

const Input = styled.input.attrs({
  // we can define static props
  type: 'password',

  // or we can define dynamic ones
  margin: props => props.size || '1em',
  padding: props => props.size || '1em'
})`
  color: palevioletred;
  font-size: 1em;
  border: 2px solid palevioletred;
  border-radius: 3px;

  /* here we use the dynamically computed props */
  margin: ${props => props.margin};
  padding: ${props => props.padding};
`;

render(
  <div>
    <Input placeholder="A small text input" size="1em" />
    <br />
    <Input placeholder="A bigger text input" size="2em" />
  </div>
);