Yomi Eluwande JavaScript Developer. Wannabe Designer and Chief Procrastinator at Selar.co and Worklogs.co

How (and when) to use React’s new Context API

4 min read 1146

So it’s not exactly news on the interwebs that React Context will be stable in the upcoming release of React, React 16.3.0. React Context is/was an experimental feature of React that received better implementation thanks to multiple PRs from contributors.

But even though it’s not news, it is worth taking a minute to learn when and how to use it. And that’s what we’ll do here.

What problem does Context API solve?

React Context is a way for a child component to access a value in a parent component.

One familiar problem in React is what is popularly known as prop drilling.

Prop drilling occurs in situations where you’re looking to get the state from the top of your react tree to the bottom and you end up passing props through components that do not necessarily need them.

React Context solves the problem of props drilling. It allows you to share props or state with an indirect child or parent.

Ordinarily, you’d use a state management library like Redux or Mobx, but what if you don’t want to? Or the data to be passed is so minute that using a state management library would be overkill.

This is where the new React Context API comes in.

What happened to the current Context API?

Well, the current Context API is considered to be unstable as it an experimental API and is likely to break in future releases of React. Also, the current and soon to be old Context API had issues with shouldComponentUpdate blocking context changes.

This happens when an intermediate component updates using shouldComponentUpdate, React will automatically assume there are no changes and reuse the entire subtree. The problem with that is if the subtree contains a context consumer, the consumer will not receive the latest context.

What’s new?

With the new React Context API, you should be familiar with three things:

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.

const Context = React.createContext();

Provider

The Provider component is used higher in the tree and accepts a prop called value.It provides a root upon which any child in that tree can access the values that are provided by that context provider.

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

The provider accepts a context value as a prop. Any matching consumer in the provider’s subtree can access it, regardless of how deeply it’s nested.

Consumer

The Consumer as the name suggests consumes the data being passed and renders the data by using a render prop API.

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

Using React Context API

Before I demonstrate how React Context can be used, let’s take a look at this example below that uses prop drilling to get some data, so that we can establish a bit of…wait for it…context.

Classic Prop Drilling

The online code editor tailored for web applications

The code block above is just a short example of how prop drilling works. We had to pass the props data from the top to the bottom even though the components don’t necessarily need it.

Now let’s see how this can be solved using React Context. To get started, you have to install the alpha version of React 16.3.

npm i react@next react-dom@next

React Context

The online code editor tailored for web applications

Let’s go through the code block above.

const JediContext = React.createContext();

We first initialise a new Context and set it to a const variable. It can be set as anything.

class JediProvider extends Component { state = { name: "Vader", side: "dark" }; render() { return ( \<JediContext.Provider value={{ state: this.state, turnGood: () =\> this.setState({ side: "good" }) }} \> {this.props.children} \</JediContext.Provider\> ); } }

Inside the JediProvider Component, we create a Provider Context inside the render() function as JediContext.Provider . JediContext.Provider accepts a prop called value which is set to the state and a function that updates the state.

Now that we have a Provider, how do we consume the data, even across parent to child components?

class App extends Component { render() { return ( \<JediProvider\> \<Vader /\> \</JediProvider\> ); } }

const Vader = props =\> { return \<Luke /\>; }; const Luke = props =\> { return \<KyloRen /\>; };

const KyloRen = props =\> { return ( \<JediContext.Consumer\> {context =\> ( \<React.Fragment\> \<p\>My grandfather is {context.state.name} \</p\> \<p\>He belonged to the {context.state.side} side\</p\> \<button onClick={context.turnGood}\>Turn\</button\> \</React.Fragment\> )} \</JediContext.Consumer\> ); };

render(\<App /\>, document.getElementById("root"));

The first thing to do would be to wrap all the children of the top level App component with the provider we created, which is, JediProvider . That means all of its children will have access to the value in the Context.

Almost like the prop drilling method above, the components are passed into each other albeit with no props, no drilling. The difference is in the bottom child which is KyloRen . The KyloRen component uses JediContext.Consumer to pass context as a render prop. Since context holds the state , you can easily use it to display the data that is required.

As seen with context.turnGood , we can also use Context to change and update the state. Whenever the button is clicked, it calls the turnGood function that was added as a value in the Provider.

Overall, this is a better solution than the prop drilling methods, you don’t have to pass props unnecessarily to component who don’t need them.

React Context

The online code editor tailored for web applications

Is it a Redux killer?

No. The new Context API has its limitations.

For example, it encourages the use of immutable or persistent data structures or strict comparison of context values which might prove difficult because many common data sources rely on mutation.

Another limitation is that the new Context API only allows for a Consumer to read values from a single Provider type, one consumer to one provider. Unlike the current API, which allows a Consumer to connect to multiple Providers.

When should you use React Context?

You can use it when all you want is simple state management, or in cases where you want to pass some props deeply without the overkill that comes with Redux or MobX.

The Context API should be updated and included in the next couple of updates for React. It will definitely be interesting to see the updates and feature changes for the Context API going forward.

Full visibility into production React apps

Debugging React applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, tracking slow network requests and component load time, try LogRocket. https://logrocket.com/signup/

LogRocket is like a DVR for web apps, recording literally everything that happens on your React app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors performance of your app with metrics like client CPU load, client memory usage, and more.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

Modernize how you debug your React apps - .

Yomi Eluwande JavaScript Developer. Wannabe Designer and Chief Procrastinator at Selar.co and Worklogs.co

Leave a Reply