Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ReactJS overriding or editing context along the hierarchy

I know that in ReactJS, "context" can be used to pass down data from a component to its ancestors. However, can this context be modified along the hierarchy? If yes, how is this behavior described?

For instance: let's say that components are nested as follows: (A -> B -> C) component B is a child of component A, and component C is a child of component B. If A passes down some data through context, it can be accessed likewise from B and C. However, can B modify this context before it is passed down to C?

like image 420
sarora Avatar asked Sep 01 '15 20:09

sarora


People also ask

Can we change context value in React?

Updating Context value js components, we cannot update this value. To switch between the two theme types, we need to pass a function as well. This function will allow us to switch between both themes. So we need to pass this function along with the dark theme via the Provider component.

What is the best method to update state in component React?

To update our state, we use this. setState() and pass in an object. This object will get merged with the current state. When the state has been updated, our component re-renders automatically.


1 Answers

Yes. Consider the following two examples, each involving three nested components. Both of these examples use the following HTML file:

File - 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>

EXAMPLE 1:

File - 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'
};

File - 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'
};

File - 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>
            );
    }
});

Upon running this example, this is the output in the console:

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]

As can be seen, in this case, ChildComponent added a new key:value pair to the context object. Hence, the object returned by the getChildContext() function of ChildComponent got ADDED to the context.

In the output, the first line of text is black, the second line of text is blue, and the final line of text is red.

EXAMPLE 2

File - 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'
};

File - 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'
};

File - 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>
            );
    }
});

Upon running this example, this is the output in the console:

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

As can be seen, in this case, ChildComponent tried to add a new key:value pair to the context. However, since the key already existed, its existing value got replaced by the new value supplied by ChildComponent. Essentially, the new value OVERRODE the previous value.

The output is the same as the first example. So in general, it can be inferred that the context can be modified by components along the hierarchy chain. Moreover, if this modification involves an existing key, the value corresponding to that key is overridden (replaced). Otherwise, the new key:value pairs are simply added to the context object.

like image 52
sarora Avatar answered Oct 06 '22 22:10

sarora