Context in React
Tags: react, javascript
Published: 2018-06-19 16:13:28

---
title: Context in React
published: true
description: The "new" context API
cover_image: https://thepracticaldev.s3.amazonaws.com/i/zlxdkownkaffccac7lpi.jpg
tags: react, javascript
---

_[Cover image by Rebecca Jackson on Flickr.](https://www.flickr.com/photos/_rebeccajackson/)_

## What

First, what is a context?

A context is a way to store and pass down data a React element tree without writing it into a prop every layer of the hierarchy. It consists of two components, a `Provider` and a `Consumer`.

A `Provider` stores some data that can be accessed via the `Consumer` somewhere in the tree below the `Provider`. So the `Consumer` has to be a descendant of the `Provider`.

A `Consumer` accesses the `Provider` data and makes it available to its `children` via a render prop. The nice thing being, a `Consumer` doesn't have to be a direct child of a `Provider` it can be anywhere in the tree below it.


## Why

Sometimes you use data inside your application that is quasi global. Sometimes it's global to the whole application, sometimes just global to a screen or page, but it is used in many places.

For example, you want to use theme information in all of your UI components, or you want to make the data of the currently logged in user available to many components, or you have an API client that needs to be configured one time and than used all over your application.

Now you could make this data simply global, but this would get unwieldy rather quick. A context is a way to do this in an encapsuled way and since none of the elements between the `Provider` and the `Consumer` know about the context or its data, it also is another way to add dependency injection into your app and make it more resilient to change.

## How

So how do you create a context? And how do you use it later?

The context API got rewritten not long ago for flexibility and ease of use. React provides a simple function to create a context.

```javascript
const Context = React.createContext();
```

This function returns an object with two attributes `Provider` and `Consumer` that contain the components which are needed to use this context later. 

A basic usage could look like this:

```javascript
<Context.Provider value="context data">
  ...
  <Context.Consumer>
    {value => <p>{value}</p>}
  </Context.Consumer>
  ...
</Context.Provider>
```

The `Provider` takes a `value` prop that becomes its `state`. The `Consumer` takes a `render` prop in form of _children as a function_. This function receives the current `value` as argument.

Often you have more complex data and a way to change this data down in the components that use it.

Here a more complex example:

```javascript
const Context = React.createContext();
class A 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}>
        <B />
      </Context.Provider>
    );
  }
}
const B = props => <div><C /></div>;
const C = props => (
  <Context.Consumer>
    {({ handleChange, data }) => (
      <div>
        <button onClick={() => handleChange(2)}>Change</button>
        <D text={data.x} />
      </div>
    )}
  </Context.Consumer>
);
const D = props => <p>{props.text}</p>;
```

We start by creating a `Context`.

Then we use it in component A which is the top of our hierarchy. The value for our `Context.Provider` is the state of `A` and a method of `A` that handles changes to this `state`. When the `state` changes, the `Context.Provider` gets a new value. `A` is also the storage of our state, the context just pipes it down the hierarchy.

In component `C` we use the `Context.Consumer`, it receives a function via its `children` render prop. If the value of the `Context.Provider` changes this function is simply called again and renders with the new value.

As you can see, component `B` which is between `A` and `C` is completely elusive to the whole context arrangement. It just renders component `C` indifferent about its implementation.

Also, component `D` and the `button` element don't know anything about context. They just get data and the change handler function passed via their props and can use them as any other prop. `D` wants the text it renders passed into its `text` prop instead of children and button is just a regular old button that executes everything passed into its `onClick` prop. So context is an extension of the dependency injection used in pure render props.

Because the pair of `Provider` and `Consumer` are created per `createContext()` call, you can even have multiple contexts. Every context is encapsuled and safe from actions of other contexts.

## Conclusion

The new context API is much more flexible than the old one and works without prop-types and since it's now stable, you can finally use it without fear that it goes away soon.

It also extends the dependency injection concepts used in render props by letting you pass down state from a component to a deep ancestor of it without telling the in-betweens anything of it.