Rakshit Soral (RKS)

@rakshitsoral

Everything you need to know about React’s Context API

Image credits: https://www.robinwieruch.de

React is one such UI library which gets frequent upgradation in terms of new features and concepts within months. One such additional concept or feature in version 16.3 gives us Context API which is an upgraded version of old concept of context in React which allow components to share data outside the parent-child relationship.

In this article, I will walk you through the basics of the new Context API and why to use it in your next React based project.

Let’s dive in!

Why do you need Context API in React?

Before we dive into the reason why React upgraded to Context API, let’s first be familiar with some basic terminologies which are used to introduce data manipulation and updation in React.

In React, Data is updated and manipulated by using some terms which we called as props and state.

Props or properties can be understood as the data or information that is being passed to the child component from a parent component.

While state can be easily understood as the data which is being managed within the component itself.

So if each component manage it own state, how could you share data between nested components? Yes, it is true that we have props to pass the data but that only works in parent-child relationship case.

For an instance, let’s take an example of an app which is composed of different types of nested components:

As seen in Image above, Child2 is the children of Child which is also child of Parent. That makes Child2 as the grandchild of Parent.

Now, let’s play with some code to understand it in a more simplest manner:

class Parent extends React.Component {
state = {
value: ‘Some value’
};

render() {
return(
<Child value={this.state.value} />
);
}
}

const Child = (props) => (
<Child2 value={props.value} />
);

const Child2 = (props) => (
<div>{props.value}</div>
);

In the above example, we are sending value from parent component (Parent here) through its child component Child, which is then supposed to be used inside component Child2. Here, Child component doesn’t care about the value (prop), it’s only passing down the prop to be used within component Child2. Now, this example might seem simple to you and you will wonder what’s the problem with that.

Let’s imagine for a second, if we not only have a Child component but Grandchild1 and Grandchild2 or further more components between Parent and Child2. In such case, you would need to pass the props further down to each of these components of the tree. But, by the definition of props mentioned above, value can be passed only in between Parent and Child.

Such kind of problem which could be a havoc for React performance is known as Prop drilling. In simpler terms, it relates to the passing down of props from the upper level i.e Parent to lower level components such as Child, Grandchild etc. in the component tree, where components in between doesn’t care about these props.

Although, you have libraries such as Redux to mitigate this kind of complexity but it’s worthless to use Redux in this case as it will make your app’s logic more complex. Nevertheless, this is where the concept of Context API in React comes into play.

When should you use React’s new Context API?

Using Context is the best fit for the use case where your codebase consists of lot of components that depends on a single piece of data, but are nested deep within the component tree.

Following image will give you an idea as in how deep your upper level, middle level and lower level components can be nested within a component tree:

Things you need to be familiar with before using React’s new Context API

As mentioned above, React’s new Context API provides a way to pass and store data down a React component tree without writing it into every layer of the component hierarchy. It does so by leveraging on two types of components:

Provider — The Provider component is used in higher hierarchy of the tree. It accepts a prop called as Value. It acts as a root component in the hierarchical tree such that any child in the tree can access the values that are provided by the context provider.

render() {return (
<Provider value={this.state.contextValue}>
{this.props.children}
</Provider>
);
}

Consumer — As the name implies, consumer consumes the data which is being passed, irregardless of how deeply nested it is located in the component tree. That means, Consumer don’t have to be necessarily be the child of Provider. Instead, it can access data from anywhere down the component tree.

A consumer renders the data by using a render prop API.

render() {return (
<Consumer>
{contextValue => <Child arbitraryProp={contextValue} />}
</Consumer>
)
}

How to use Context in your React Application?

Now that you are pretty much familiar with what’s up to the new Context API, now is the time for you to understand how to use Context in an application.

In React, you have a predefined function to create a Context:

const Context = React.createContext();

React.createContext is used to initialise the Context and it’s passed the initial value. It returns an object with a Provider and a Consumer. Providers and consumers come in pairs, that is, for each provider, there is a corresponding consumer.

The examples explained above are pretty much simpler to understand. Though, you always will have to play with more complex data and find a way to store that data down in the component tree so that other components could use it.

Let’s now re-implement the above example with the context API:

const Context = React.createContext();
class Parent extends React.Component {
state = { x: 1 };
handleContextChange = x => this.setState({ x });
render() {
const contextValue = {
data: this.state,
handleChange: this.handleContextChange
};
return (
<Context.Provider value={contextValue}>
<Child/>
</Context.Provider>
);
}
}
const Child = props => <div><GrandChild/></div>;
const GrandChild = props => (
<Context.Consumer>
{({ handleChange, data }) => (
<div>
<button onClick={() => handleChange(2)}>Change</button>
<Child2 text={data.x} />
</div>
)}
</Context.Consumer>
);
const Child2 = props => <p>{props.text}</p>;

In the above code snippet, we have started by initialising a context. Then we have use it in the top hierarchy which belongs to the component Parent. The State of Parent component is the value of Context.Provider. Upon changing the state, the Context.Provider gets a new value. Parent component is also used as the storage of our storage of the state so that the context can pass it down the hierarchy.

In the component GrandChild, we have used the Context.Consumer which receives a function via its children render prop. Upn changing the value of Context.Provider, this function is invoked repeatedly and renders with the new value finally.

Here, component Child which is between Parent and GrandChild is not aware about the whole context arrangement. Same is with component Child 2 and button element as they also don’t know about the context. These components just receive the data and the changeHandler function passed via their props and can use them further as any other prop.

Final Words

React’s new Context API is definitely not an alternative to the state management libraries such as Redux or MobX. Neither, it relies on passing a context down the component down the component tree. Instead, it provides a provider-consumer component pairs to communicate between the nested components in the hierarchy.

The top level components provide the data and the lower level components consume it without having to pass the data down the component hierarchical tree level-by-level.

With this article, you are good to start with using the React’s Context API in your apps. If you further want more relevant information about the API, don’t forget to go through the official documentation.

Topics of interest

More Related Stories