ReactJS覆盖或编辑层次结构中的上下文

sar*_*ora 7 components overriding reactjs

我知道在ReactJS中,"context"可以用来将数据从组件传递给它的祖先.但是,可以在层次结构中修改此上下文吗?如果是,那么这种行为是如何描述的?

例如:假设组件嵌套如下:(A - > B - > C)组件B是组件A的子组件,组件C是组件B的子组件.如果A通过上下文传递一些数据,它同样可以从B和C访问.但是,B可以在传递给C之前修改此上下文吗?

sar*_*ora 9

是.考虑以下两个示例,每个示例涉及三个嵌套组件.这两个示例都使用以下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>
Run Code Online (Sandbox Code Playgroud)

例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'
};
Run Code Online (Sandbox Code Playgroud)

文件 - 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'
};
Run Code Online (Sandbox Code Playgroud)

文件 - 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>
            );
    }
});
Run Code Online (Sandbox Code Playgroud)

运行此示例时,这是控制台中的输出:

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]
Run Code Online (Sandbox Code Playgroud)

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

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

例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'
};
Run Code Online (Sandbox Code Playgroud)

文件 - 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'
};
Run Code Online (Sandbox Code Playgroud)

文件 - 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>
            );
    }
});
Run Code Online (Sandbox Code Playgroud)

运行此示例时,这是控制台中的输出:

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
Run Code Online (Sandbox Code Playgroud)

可以看出,在这种情况下,ChildComponent尝试将新key:value对添加到上下文中.但是,由于密钥已经存在,其现有价值被提供的新值取代ChildComponent.从本质上讲,新值超过了之前的值.

输出与第一个示例相同.因此,一般而言,可以推断出上下文可以由层次链上的组件修改.此外,如果此修改涉及现有密钥,则覆盖(替换)与该密钥对应的值.否则,新的键:值对将简单地添加到上下文对象中.

  • 感谢您抽出宝贵时间回答这个问题.你的答案是有帮助的,但如果你考虑让它更简洁,那将是很好的.那里有很多东西,需要花费很多时间才能完成. (3认同)

Sor*_*ine 5

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

考虑组件的层次结构:

<A>
  <B>
    <C/>
  </B>
</A>
Run Code Online (Sandbox Code Playgroud)

提供以下背景:

class A extends React.Component {

    ...

    getChildContext() {
        return {
            x: 'a',
            y: 'a'
        };
    }

    ...

}

class B extends React.Component {

    ...

    getChildContext() {
        return {
            y: 'b',
            z: 'b'
        };
    }

    ...

}
Run Code Online (Sandbox Code Playgroud)

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

{
    x: 'a', // Provided by A
    y: 'b', // Provided by A and B, overriden by B's value
    z: 'b'  // Provided by B
}
Run Code Online (Sandbox Code Playgroud)