DEV Community

Daniel - JS Craft
Daniel - JS Craft

Posted on

How to use the new React context API - tutorial & screencast

Have you ever passed a property to a React component for no other reason but just to be able to pass it down to a child of that component? Well, this is exactly what the new React Context API tries to fix.

note: this a repost from the original Hackernoon article that can be found here. If you like this article sign up for my email list so I can share with you the next screencasts and tutorials!

Prefer Video?

Prefer video tutorials? I made this tutorial also into a video, which can be found below:

React context tutorial

The problem?

For example in the example below:

  • we have some data, namely a number with the value of 10
  • we need the data in the Red component and also in the Green one
  • the Green component is a child of the Blue component that is a child of the Red component
  • so, most probably, we will need to send the data from the Red component to the Blue one just to be able to send it to the Green one React context example

In this point our code would look something like this:

const Green = (props) => (
  <div className="green">{props.number}</div>
)
const Blue = (props) => (
  <div className="blue">
    <Green number={props.number} />
  </div>
)

class Red extends Component {
  state = {
    number : 10
  }
  render() {
    return  <div className="red">
      {this.state.number}
      <Blue number={this.state.number} />
    </div>
  }
}
Enter fullscreen mode Exit fullscreen mode

We have to send the data to the Blue component only to “drill” it down to the Green component. And this is a simple case. Imagine what will happen if we have ten levels of parent-child React components.

Till React 16.3 the standard solution to problems like this one was Redux or Mobx or any other library that deals with state management. But now, we have the solution embedded into React.

The solution: state management with React Context?

What React Context is allowing us to do is to define data stores and access them where they are needed. We don’t have to pass down data through properties any more. With React Context we can define something like an “application global state” and use that data where needed.

Who to use React Context ?

There are two main steps to setup the React context into your application :

  1. setup a context provider & define the data you want to store
  2. use a context consumer where ever you need the data from the store

In order to make the context provider we will need to make a context via React.createContext. We will call our context AppContext:

const AppContext = React.createContext()
Enter fullscreen mode Exit fullscreen mode

The newly created AppContext will be used to build a context provider component. This provider will store, in its state, the data we need and it will wrap all of the content of the Red component:

class AppProvider extends Component {
  state = {
    number : 10,
  }
render() {
    return <AppContext.Provider value={this.state}>
    </AppContext.Provider>
  }
}

//...

class Red extends Component {
  render() {
    return  <AppProvider> 
        <div className="red">
          <Blue />
        </div>
    </AppProvider>
  }
}
Enter fullscreen mode Exit fullscreen mode

Long story short: by wrapping everything in this AppProvider we can easily inject the data from the value attribute where needed. Given the fact that AppProvider will be used as a wrapper component it’s important to use the {this.props.children} in the render method.

Now, with the provider installed if we want to access some data from the provider we can easily use the context consumer.

<AppContext.Consumer>
      {(context) => context.number}
</AppContext.Consumer>
Enter fullscreen mode Exit fullscreen mode

All the data that we added to the value property of AppContext.Provider is now made available by the context parameter of the arrow function.

At this point our code will look something this

const AppContext = React.createContext()
class AppProvider extends Component {
  state = {
    number : 10
  }
render() {
    return <AppContext.Provider value={this.state}>
      {this.props.children}
    </AppContext.Provider>
  }
}
const Green = () => (
  <div className="green">
      <AppContext.Consumer>
        {(context) => context.number}
      </AppContext.Consumer>
  </div>
)
const Blue = () => (
  <div className="blue">
    <Green />
  </div>
)

class Red extends Component {
  render() {
    return  <AppProvider> 
        <div className="red">
          <AppContext.Consumer>
            {(context) => context.number}
          </AppContext.Consumer>
          <Blue />
        </div>
    </AppProvider>
  }
}
Enter fullscreen mode Exit fullscreen mode

Please note that we are not anymore passing down the number property to the Blue component or the Green one anymore. All of this data is now handled by the React Context mechanism.

Using actions and modifying data in the React Context

Unless you are working on a very basic app you will need a way to update/change the data that comes from the React Context. The minimal example can be a button that will increment the number from our data.

React context example

We will need something that is the alternative from the Mobx or Redux actions.

This is quite easy to achieve. What we will to do is to define a function on the state of the AppProvider context, and do the required updates onto the state data.

class AppProvider extends Component {
 state = {
    number : 10,
    inc: () => {
      this.setState({number: this.state.number + 1})
    }
  }
  //...
}
Enter fullscreen mode Exit fullscreen mode

Having the action defined we can use it through a AppContext.Consumer and call it in a onClick event:

const Blue = () => (
  <div className="blue">
    <AppContext.Consumer>
        {(context) => <button onClick={context.inc}>INC</button>}
      </AppContext.Consumer>
    <Green />
  </div>
)
Enter fullscreen mode Exit fullscreen mode

Our final code will now look something like this :

import React, { Component } from 'react'
const AppContext = React.createContext()
class AppProvider extends Component {
 state = {
    number : 10,
    inc: () => {
      this.setState({number: this.state.number + 1})
    }
  }
 render() {
    return <AppContext.Provider value={this.state}>
      {this.props.children}
    </AppContext.Provider>
  }
}
const Green = () => (
  <div className="green">
     <AppContext.Consumer>
        {(context) => context.number}
      </AppContext.Consumer>
  </div>
)
const Blue = () => (
  <div className="blue">
    <AppContext.Consumer>
        {(context) => <button onClick={context.inc}>INC</button>}
      </AppContext.Consumer>
    <Green />
  </div>
)
Enter fullscreen mode Exit fullscreen mode

Still in its early phase React 16.3 Context API can be used as an alternative to the classic state management alternative if your sole purpose of using a state management library is avoiding prop drilling.

I hope you found this article helpful! Let me know if there are other things you’re would want to learn in the realm of React, Mobx and Javascript.

If you liked this article sign up for my email list so I can share with you the next screencasts and tutorials!

Top comments (2)

Collapse
 
shasu01 profile image
shasu01

AppContext is not defined when the components are on different files

Collapse
 
syamjayaraj profile image
Syamlal CM • Edited

The same issue occurred for me. But I found the solution also.

Create a file AppContext.js separately.

//AppContext.js
import React from "react";
const AppContext = React.createContext();
export default AppContext;

Now import this file where AppContext is required.