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

Joe*_*dee 11 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;
Run Code Online (Sandbox Code Playgroud)

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

警告:React无法识别somePropDOM元素上的prop.如果您有意希望它作为自定义属性显示在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;
Run Code Online (Sandbox Code Playgroud)

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

Eli*_*ant 48

2020 年更新:使用瞬态道具

5.1.0 版本中,您可以使用瞬态道具。这样您就不需要额外的包装器,即减少了不必要的代码:

瞬态 props 是一种新模式,用于传递仅由样式组件显式使用的 props,而不打算向下传递到更深的组件层。以下是您如何使用它们:

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

render(<Comp $fg="red">I'm red!</Comp>);
Run Code Online (Sandbox Code Playgroud)

注意道具上的美元符号 ($) 前缀;这将其标记为瞬态和样式组件知道不将其添加到呈现的 DOM 元素或将其进一步向下传递到组件层次结构。

新的答案应该是:

样式组件:

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

父组件:

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

  • 我真的希望样式组件文档已更新以包含此内容 (7认同)
  • 更新了答案中的文档 - https://styled-components.com/docs/api#transient-props (3认同)

tsk*_*tne 14

正如vdanchenkov这个样式组件github问题的建议你可以解构道具并只传递相关的道具Resizable

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


Fel*_*ger 9

对于那些因为 SC 和 react-router 的Link.

这与@tskjetne 的答案基本相同,但具有 JS 语法风格。

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

  • 如果我们必须像这样使用它,样式组件就不再有意义了。它本来可以是一个不错的“样式(链接)”“……”但不是。 (5认同)
  • 我怎么没想到这个?非常感谢! (2认同)

Cha*_*shu -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;
Run Code Online (Sandbox Code Playgroud)

我们还可以使用“ 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>
); 
Run Code Online (Sandbox Code Playgroud)