Passing Data Across Components with Contexts (childContextTypes, getChildContext(), contextTypes) in ReactJS

Using React Contexts we can communicate across a hierarchy of Components. To understand this, think of a widget represented by a View component which has lots of child view components. You might use/re-use this component and want to pass certain properties or attributes that are relevant to different child components affecting the overall state (look and behaviour) of the main component in combination. Now one way to achieve this is by using props. But imagine passing an attribute all the way down from the parent to a child at the 5th level in the hierarchy. At every component level the property passed from the parent will have to be accessed (this.props.propName) and further passed down. This can get really messy. So let’s see how contexts can be used to pass data across components in a much elegant manner.

childContextTypes, getChildContext(), contextTypes

A fairly simple example should make it all crystal clear:

What's the one thing every developer wants? More screens! Enhance your coding experience with an external monitor to increase screen real estate.

class A extends React.Component {
  getChildContext() {
    return {
      framework: 'React',
      language: 'JavaScript'
    };
  }

  render() {
    return (
      <B />
    );
  }
}

class B extends React.Component {
  render() {
    return (
      <div>
        <p>Framework: {this.context.framework}</p>
        <C />
      </div>
    );
  }
}

class C extends React.Component {
  render() {
    return (
      <p>Language: {this.context.language}</p>
    );
  }
}

A.childContextTypes = {
  framework: React.PropTypes.string.isRequired,
  language: React.PropTypes.string.isRequired
};

B.contextTypes = {
  framework: React.PropTypes.string.isRequired
};

C.contextTypes = {
  language: React.PropTypes.string.isRequired
}

React.render(<A />, document.body);

It all starts with childContextTypes that is use to specify the schema of our context that has to be passed down our component hierarchy. Then the real context data is specified in the getChildContext() method which returns an object passed down to all the children rendered by the component A. Note the object returned must contain keys specified in childContextTypes. If there’s an unmatch between what is specified and what is returned, then React will throw a warning.

Now whichever elements the children want to access, must be whitelisted using contextTypes object which looks similar to childContextTypes specified by the parent. If you notice, B view component as well as C specify the elements they want access to.

B.contextTypes = {
  framework: React.PropTypes.string.isRequired
};

C.contextTypes = {
  language: React.PropTypes.string.isRequired
}

If they try to access anything apart from what they’ve whitelisted using contextTypes, then that won’t work as those keys/elements won’t be defined on this.context (or undefined will be evaluated). What this basically means is this.context for both the child components would look like this:

// this.context for B
{ framework: 'React' }

// this.context for C
{ language: 'JavaScript' }

Wrapping Up!

Contexts arn’t properly document yet, so it’s quite possible the current way of passing data may partially or entirely change by the time React 1.0 is out. Make sure you don’t confuse contexts with props nor states. The way they’re specified as well as accessed is different from props or states. Although a state change could affect the context which would eventually impact the looks (UI) or behaviour of the component being rendered.

Author: Rishabh

Rishabh is a full stack web and mobile developer from India. Follow me on Twitter.

Leave a Reply

Your email address will not be published. Required fields are marked *

*