基于父母的道具的样式化组件中的条件渲染

时间:2020-10-17 22:05:22

标签: reactjs styled-components

我将如何基于其父组件的道具将条件样式应用于样式组件?

下面是我当前代码的高级示例设置:

// File 1: GrandParent.js

import React, { useState } from 'react';
import Parent from './parent';

export default function GrandParent() {
    const [ isExpanded, setIsExpanded ] = useState(false);

    render (
        <>
            <Parent isExpanded={isExpanded} />
            ...other Stuff
        </>
    );
}
// File 2: Parent.js

import React from 'react';
import styled from 'styled-components';
import mediaQueries from './settings';

export default function Parent(props) {
    render (
        <div className={props.isExpanded ? `expanded` : ``}>
            ... other stuff
            <Child>I'm a child.</Child>
        </>
    );
}

const Child = styled.div`
    background-color: "red";

    .expanded & {
        background-color: "blue";

        ${mediaQueries.desktop`
            background-color: "navy";
        `}
    }
`;

本质上,我想要的是让<Child>样式的组件知道<Parent>的道具,以便可以有条件地对其进行样式设置。目前,我只是有条件地将类名应用于<Parent>内的div,然后使用该类名将样式应用于<Child>。但是感觉不像是一种非常样式化的组件或React的处理方式。

我想做的是更多这样的事情:

const Child = styled.div`
    background-color: ${props => props.isExpanded ? 'blue' : 'red'};
`;

但是我是否有办法不必在<Child>上传递'isExpanded'作为道具呢?在我的实际代码中,还有更多<Parent>的子代也需要知道'isExpanded'的状态以用于样式设计,我真的不想将那个道具单独传递给他们

我认为Context API可能是这里的关键,但是我已经在React树中的GrandParent上方几级使用了上下文来进行全局样式设置,而且我担心如果尝试嵌套第二个上下文(可能将其包装在<Parent>周围,以使<Parent>及其所有子代知道'isExpanded'的状态),然后<Parent><Child>可能无法访问外部上下文...或者不是上下文嵌套如何工作?

我只知道我仍然需要<Parent><Child>才能从外部上下文访问某些主题设置。而且我不知道在<Parent>级别引入第二上下文仅仅是跟踪该单个“ isExpanded”道具的状态是否过大。

这里的另一个要求是,我还需要<Child>才能处理其条件样式内的媒体查询(例如,如果'isExpanded'为true且为桌面视口,则仅应用某些样式)。

什么是正确的设置方式?

2 个答案:

答案 0 :(得分:1)

您是正确的。上下文是必经之路。

上下文被设计为轻量级的跨组件数据存储,在这种情况下使用2个上下文绝对不是矫kill过正。实际上,此用例几乎就是为Context创建的。 (有趣的是,在工作中,我们使用了数十个嵌套上下文)。

export const ExpandedContext = createContext();
export default function GrandParent() {
    const [ isExpanded, setIsExpanded ] = useState(false);
    
    render (
        <ExpandedContext.Provider value={{ isExpanded }}>
            <Parent />
            ...other Stuff
        <ExpandedContext.Provider/>
    );
}

不幸的是,无法访问样式化组件内部的上下文,因此您必须通过props传递值。

export default function Parent(props) {
    const { isExpanded } = useContext(ExpandedContext);
    render (
        <div>
            ... other stuff
            <Child isExpanded={isExpanded}>I'm a child.</Child>
        </div>
    );
}

答案 1 :(得分:1)

您可以将父级容器div设置为样式组件,并将refer设置为Child。像这样:

export default function Parent(props) {
    render (
        <ParentContainer isExpanded={props.isExpanded}>
            ... other stuff
            <Child>I'm a child.</Child>
        </ParentContainer>
    );
}

const Child = styled.div`
    // ...
`;

const ParentContainer = styled.div`
  > ${Child} {
    background-color: ${props => props.isExpanded ? 'blue' : 'red'};
  }
`;