如何从 parent 的 styled-component 访问 child 的道具?

How to access child's props from parent's styled-component?

我有这种结构:

  <Wrapper activeTextColor="red">
    <Text active={true}>Text 1</Text>
    <Text active={false}>Text 2</Text>
  </Wrapper>

Styled-components 应该是这样的:

const Text = styled.p``;

const Wrapper = styled.div`
  ${Text} {
    ${props =>
      props.activeTextColor &&
      css`
        /* How to make color red based on "active" attribute of Text element? */
      `}
  }
`;

如何从 parent 的 styled-component 访问 child 的道具?

这是一个live example

const Text = styled.p`color: ${props => props.active ? "red" : "palevioletred"};`;

你不能(据我所知)。但是您可以从子组件访问父组件的 props(反之亦然)。这似乎完成了您想要做的事情。

简答:

您必须将父属性传递给子组件

在父组件 <Wrapper /> 中,您必须克隆您的子组件并将 activeTextColor 传递给子组件:

const StyledWrapper = styled.div``;

class Wrapper extends React.Component {
  render() {
    const { children, activeTextColor } = this.props;
    return (
     <StyledWrapper activeTextColor={activeTextColor}>
       {React.Children.map(children, child =>
         React.cloneElement(child, {
           activeTextColor: activeTextColor
         })
       )}
     </StyledWrapper>
    );
  }
}

现在可以从 Text 组件访问 activeTextColoractive

const Text = styled.p`
  ${props => css`
    color: ${props.active ? activeTextColor : "#000"};
  `}
`;

另一个选项:

在上述情况下,使用 ThemeProvider/ThemeConsumer 可能更有意义。如果您知道 activeTextColor 将变为红色(也许您正在处理设计令牌),则使用以下方式访问活动颜色:

${props => css`
  background: ${props.active ? props.theme.activeTextColor : '#000'};
`}

详细答案以及为什么有人想要这样做):

这扩展了上面的简短回答。在某些时候,您可能需要访问父组件中的父道具,以及子组件中的子道具和父道具。

一个现实世界的例子就像标签一样。我有两种不同的选项卡样式/变体,Tabs 容器组件和 Tab 都需要自己的样式,具体取决于自己的道具。它是一种具有两种不同样式的组件。

嵌套样式组件将不起作用。所以你最终会得到这样的结果。


const StyledTabs = styled.div`
  display: flex;
  justify-content: flex-start;
  ${props =>
    props.variant === "wizard" &&
    css`
      justify-content: space-between;
    `}
`;

const StyledTab = styled.p`
  font-size: 14px;
  white-space: nowrap;
  font-family: sans-serif;
  border: 1px solid #ddd;
  padding: 15px;
  ${props => css`
    background: ${props.active ? "#fff" : "#f6f6f6"};
  `}

  ${props =>
    props.variant === "box" &&
    css`
      & {
        border-right: 0 none;
        &:last-child {
          border-right: 1px solid #ddd;
        }
        border-top: ${props.active
          ? "2px solid lightseagreen"
          : "1px solid #ddd"};
        border-bottom: ${props.active ? "none" : "1px solid #ddd"};
      }
    `}

  ${props =>
    props.variant === "wizard" &&
    css`
      & {
        margin-right: 20px;
        text-align: center;
        line-height: 40px;
        height: 40px;
        width: 40px;
        border-radius: 50%;
        color: ${props.active ? "#fff" : "#000"};
        ${props.active && "background: lightseagreen"};
      }
    `}
`;

class Tabs extends React.Component {
  render() {
    const { children, variant } = this.props;
    return (
      <StyledTabs variant={variant}>
        {React.Children.map(children, child =>
          React.cloneElement(child, {
            variant: variant
          })
        )}
      </StyledTabs>
    );
  }
}

class Tab extends React.Component {
  render() {
    const { children, variant, active } = this.props;
    return (
      <StyledTab variant={variant} active={active}>
        {children}
      </StyledTab>
    );
  }
}

const App = () => (
  <div>
    <Tabs variant="box">
      <Tab active={true}>Tab 1</Tab>
      <Tab>Tab 2</Tab>
      <Tab>Tab 3</Tab>
    </Tabs>
    <Tabs variant="wizard">
      <Tab active={true}>Step 1</Tab>
      <Tab>Step 2</Tab>
      <Tab>Step 3</Tab>
    </Tabs>
  </div>
);

render(<App />, document.getElementById("root"));

完整示例: https://codesandbox.io/s/upbeat-thunder-wfo2m

styled-component 的相关问题GitHub: https://github.com/styled-components/styled-components/issues/1193

Whosebug 上有不少相关问题,但我认为没有多少明确的答案: react-native with styled-components parent prop How to style a child component from a parent styled component, considering passed props