【问题标题】:ReactJS overriding or editing context along the hierarchyReactJS 沿层次结构覆盖或编辑上下文
【发布时间】:2015-11-27 05:34:43
【问题描述】:

我知道在 ReactJS 中,“上下文”可用于将数据从组件传递给其祖先。但是,可以沿层次结构修改此上下文吗?如果是,如何描述这种行为?

例如:假设组件嵌套如下: (A -> B -> C) 组件 B 是组件 A 的子组件,组件 C 是组件 B 的子组件。如果 A 向下传递一些数据上下文,同样可以从 B 和 C 访问。但是,B 可以在将上下文传递给 C 之前对其进行修改吗?

【问题讨论】:

    标签: reactjs overriding components


    【解决方案1】:

    是的。考虑以下两个示例,每个示例都涉及三个嵌套组件。这两个示例都使用以下 HTML 文件:

    文件 - index.html

    <!DOCTYPE html>
    <html>
      <head>
        <title>Hello React</title>
        <!-- Not present in the tutorial. Just for basic styling. -->
        <link rel="stylesheet" href="css/base.css" />
        <script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.13.0/react.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.13.0/JSXTransformer.js"></script>
      </head>
      <body>
        <div id="content"></div>
        <script type="text/jsx" src="components/ParentComponent.jsx"></script>
        <script type="text/jsx" src="components/ChildComponent.jsx"></script>
        <script type="text/jsx" src="components/GrandchildComponent.jsx"></script>
    
        <script type="text/jsx">
          React.render(<ParentComponent />, document.getElementById('content'));
        </script>
      </body>
    </html>
    

    示例 1:

    文件 - ParentComponent.jsx

    var ParentComponent = React.createClass({
    
        render: function () {
            console.log("context in render method of ParentComponent: ");
            for(var propName in this.context)
            {
                console.log(propName + ": " + this.context[propName]);
            }
    
            return (
                <div>
                    <h1>Text displayed by ParentComponent</h1>
                    <ChildComponent />
                </div>
                );
        },
    
        //for sending to descendants
        childContextTypes: {
            styleA: React.PropTypes.object,
        },
    
        getChildContext() {
            return {
                styleA: customStyleA
            };
        }
    });
    
    var customStyleA = {
        color: 'blue'
    };
    

    文件 - ChildComponent.jsx

    var ChildComponent = React.createClass({
        contextTypes: {
            styleA: React.PropTypes.object
        },
    
        render: function () {
    
            console.log("context in render method of ChildComponent: ");
            for(var propName in this.context)
            {
                console.log(propName + ": " + this.context[propName]);
            }
    
            return (
                <div>
                    <h1 style={this.context.styleA}>Text displayed by ChildComponent</h1>
                    <GrandchildComponent />
                </div>
                );
        },
    
        //for sending to descendants
        childContextTypes: {
            styleB: React.PropTypes.object,
        },
    
        getChildContext() {
            return {
                styleB: customStyleB
            };
        }
    });
    
    var customStyleB = {
        color: 'red'
    };
    

    文件 - GrandchildComponent.jsx

    var GrandchildComponent = React.createClass({
        contextTypes: {
            styleA: React.PropTypes.object,
            styleB: React.PropTypes.object
        },
    
        render: function () {
    
            console.log("context in render method of GrandchildComponent: ");
            for(var propName in this.context)
            {
                console.log(propName + ": " + this.context[propName]);
            }
    
            return (
                <h1 style={this.context.styleB}>Text displayed by GrandchildComponent</h1>
                );
        }
    });
    

    运行此示例后,控制台中的输出如下:

    context in render method of ParentComponent:
    context in render method of ChildComponent: 
    styleA: [object Object]
    context in render method of GrandchildComponent: 
    styleA: [object Object]
    styleB: [object Object]
    

    可以看出,在这种情况下,ChildComponent 向上下文对象添加了一个新的key:value 对。因此,ChildComponent 的getChildContext() 函数返回的对象被添加到上下文中。

    在输出中,第一行文字为黑色,第二行文字为蓝色,最后一行文字为红色。

    示例 2

    文件 - ParentComponent.jsx

    var ParentComponent = React.createClass({
    
        render: function () {
            console.log("context in render method of ParentComponent: ");
            for(var propName in this.context)
            {
                console.log(propName + ": " + this.context[propName]);
            }
    
            return (
                <div>
                    <h1>Text displayed by ParentComponent</h1>
                    <ChildComponent />
                </div>
                );
        },
    
        //for sending to descendants
        childContextTypes: {
            styleA: React.PropTypes.object,
        },
    
        getChildContext() {
            return {
                styleA: customStyleA
            };
        }
    });
    
    var customStyleA = {
        color: 'blue'
    };
    

    文件 - ChildComponent.jsx

    var ChildComponent = React.createClass({
        contextTypes: {
            styleA: React.PropTypes.object
        },
    
        render: function () {
    
            console.log("context in render method of ChildComponent: ");
            for(var propName in this.context)
            {
                console.log(propName + ": " + this.context[propName]);
            }
    
            return (
                <div>
                    <h1 style={this.context.styleA}>Text displayed by ChildComponent</h1>
                    <GrandchildComponent />
                </div>
                );
        },
    
        //for sending to descendants
        childContextTypes: {
            styleA: React.PropTypes.object,
        },
    
        getChildContext() {
            return {
                styleA: customStyleB
            };
        }
    });
    
    var customStyleB = {
        color: 'red'
    };
    

    文件 - GrandchildComponent.jsx

    var GrandchildComponent = React.createClass({
        contextTypes: {
            styleA: React.PropTypes.object,
            styleB: React.PropTypes.object
        },
    
        render: function () {
    
            console.log("context in render method of GrandchildComponent: ");
            for(var propName in this.context)
            {
                console.log(propName + ": " + this.context[propName]);
            }
    
            return (
                <h1 style={this.context.styleA}>Text displayed by GrandchildComponent</h1>
                );
        }
    });
    

    运行此示例后,控制台中的输出如下:

    context in render method of ParentComponent: 
    context in render method of ChildComponent: 
    styleA: [object Object]
    context in render method of GrandchildComponent: 
    styleA: [object Object]
    styleB: undefined
    

    可以看出,在这种情况下,ChildComponent 尝试将新的 key:value 对添加到上下文中。但是,由于密钥已经存在,其现有值被ChildComponent 提供的新值替换。本质上,新值 OVERRODE 之前的值。

    输出与第一个示例相同。所以总的来说,可以推断出上下文可以被层次链上的组件修改。此外,如果此修改涉及现有键,则与该键对应的值将被覆盖(替换)。否则,只需将新的键:值对添加到上下文对象中。

    【讨论】:

    • 感谢您抽出宝贵时间回答这个问题。您的回答很有帮助,但如果您考虑让它更简洁一点,那就太好了。那里发生了很多事情,而且需要相当多的时间才能完全接受。
    • @Lezard 这些答案确实需要 TL:DR... 长答案与好的答案无关。最好的答案用尽可能少的文字或 TL:DR 来解释问题。读完后,我忘记了以前的东西,因为它太长了
    【解决方案2】:

    是的,任何组件都可以通过提供上下文对象本身来扩展其子代传递的上下文。组件提供的上下文将与其父组件提供的上下文合并。这意味着可以随意添加或覆盖上下文对象中的键。

    示例

    考虑组件的层次结构:

    <A>
      <B>
        <C/>
      </B>
    </A>
    

    提供以下上下文:

    class A extends React.Component {
    
        ...
    
        getChildContext() {
            return {
                x: 'a',
                y: 'a'
            };
        }
    
        ...
    
    }
    
    class B extends React.Component {
    
        ...
    
        getChildContext() {
            return {
                y: 'b',
                z: 'b'
            };
        }
    
        ...
    
    }
    

    然后C 将收到以下上下文对象:

    {
        x: 'a', // Provided by A
        y: 'b', // Provided by A and B, overriden by B's value
        z: 'b'  // Provided by B
    }
    

    【讨论】:

    • 感谢@sarora 的回答。为了清楚起见,刚刚发布了这个较短的版本。
    猜你喜欢
    • 1970-01-01
    • 2012-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多