React Context API: What’s it all about?

React Context API

Before getting into the article, I hope you have a basic understanding about React and Javascript. If not I highly recommend you to go through React official documentation and grab a small idea about what is React and how does it work.

Introduction

The issue:

If you are an expert on React of if you have some level of experience with React or React Native development, you might have come across with different difficult situations like where you need to pass the data deep down in the child component hierarchy, that becomes cumbersome when you have a very deep child component hierarchy. That’s even if the intermediate children do not use those props, you need to pass from top parent to very bottom child component, which seems to be an ugly way of handling props.

Solution:

That’s why there are many alternative methods and frameworks arose to address this issue, the most popular framework is the Redux, All of these became popular up until React 16.3, as React itself did not have a proper stable solution to that issue.

Context provides a way to pass data through the component tree without having to pass props down manually at every level. — React Definition on Context API

As stated above, that’s how the React team defines its new Context API implementation, in which they are trying to solve the above-mentioned issue by providing a set of API functions that is Context provides a way to share values between components without having to explicitly pass a prop through every level of the tree. Let’s look at more details about the new React Context API.

NOTE: Context API was available in the older version of. REACT but it’s was not recommended. Since mars 2018, the React team publish a new version 16.3 using RenderProp pattern to pass data to the children, Also with React 16.6 there are some new additions to the Context API such as contextType

When to use the Context API

In fact, any situation where you have to pass a prop through a component so it reaches another component somewhere down the tree is where you can use the Context API.

You can think of it as a situation where you want to share a set of data that are global to the tree of React components, such as “auth data”, “theme”, “language” etc. Then it will be an ideal place to use the React new Context API functions. So let’s look at how we can use those features.

How to use the Context API

Before getting into more details of Context API features, let’s first look at a simple example code where we can improve using the Context API features, Once we have a small sense of what is Context API, then we will look into a more solid example to fully understand the React Context API functions.

So for the small example think of a scenario where we need to change the Application component’s styles based on the currently selected Application theme. [Please I’ll be using the same example as the React official documentation as it is more relevant and simple, later in this article, we shall look into more complete and detailed example on Context API features.]

class App extends React.Component {
render() {
return <Toolbar theme="dark" />;
}
}

function Toolbar(props) {
// The Toolbar component must take an extra "theme" prop
// and pass it to the ThemedButton. This can become painful
// if every single button in the app needs to know the theme
// because it would have to be passed through all components.
return (
<div>
<ThemedButton theme={props.theme} /> </div>
);
}

class ThemedButton extends React.Component {
render() {
return <Button theme={this.props.theme} />;
}
}

Now let’s look at how we can achieve the same thing using React Context API features, Context lets us pass a value deep into the component tree without explicitly threading it through every component.

// Create a context for the current theme (with "light" as the //default).
const ThemeContext = React.createContext('light');
class App extends React.Component { render() {
// Use a Provider to pass the current theme to the tree below.
// Any component can read it, no matter how deep it is.
// In this example, we're passing "dark" as the current value.

return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
}

// A component in the middle doesn't have to
// pass the theme down explicitly anymore.
function Toolbar() {
return (
<div>
<ThemedButton />
</div>
);
}

class ThemedButton extends React.Component {
// Assign a contextType to read the current theme context.
// React will find the closest theme Provider above and use
// its value.
// In this example, the current theme is "dark".

static contextType = ThemeContext;
render() {
return <Button theme={this.context} />;
}
}

I hope you have some idea about what is Context API and what we can achieve using its features.

The Process:

  1. Create a Context with some global data which should be shared between multiple React components.
const ThemeContext = React.createContext('light');

NOTE:
The defaultValue argument (i.e : In here ‘light’) is only used when a component does not have a matching Provider above it in the tree. This can be helpful for testing components in isolation without wrapping them.

Passing undefined as a Provider value does not cause consuming components to use defaultValue.

2. Create a Provider for the created context and pass value, and then Wrap
Child Components using that Provider.

<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>

3. Consume the Context values from the Created Context from the Class component.

NOTE:
Consuming Context value will be different based on the type of the React component, In Class base React Component you can access any context using contextType[New feature in React 16.6], In Function based React Component you can access using useContext hook.

static contextType = ThemeContext;render() {
return <Button theme={this.context} />;
}

I hope you have a good understanding of the React Context API concept and it’s usage to some extend. Now I want to show you different ways of Consuming created Context and its values inside React components.

How to Consume Context

In the previous section, we looked at one way of consuming created Context. In this section let’s look at all the possible ways to consume a created Context. Accessing Context will be different based on the type of the React Componet, as you probably know there are two main types of React Components, such as Function and Class Components, so let’s look at how to access Context inside each of them.

Let’s assume we create a Context called ThemeContext and All of the following Components wrapped as Child components inside a Provider component which is created using the ThemeContext.

Accessing Context inside Function Components

Method: 1 Using useContext hook:

NOTE:
Value pass to useContext should be assigned to a Context object created by React.createContext().

import React, { useContext } from 'react';
import ThemeContext from './context';
const ThemedButton = () => {

const theme = useContext(ThemeContext);

return (
<Button theme={theme} />
);
}

Method: 2 Using Consumer Component:

NOTE:
Consumer is a React component which subscribes to context changes. It lets you subscribe to a context within a function component.

import React from 'react';
import ThemeContext from './context';
const ThemedButton = () => {

return (
<ThemeContext.Consumer>
{({ theme }) => (
<Button theme={theme} />
)}
</ThemeContext.Consumer>
);
}

Accessing Context inside Class Components

Method: 1 Using contextType property on a class:

NOTE:
- contextType property on a class should be assigned to a Context object created
by React.createContext(). This lets you consume the nearest current value of that Context type using this.context inside your class component.

- Also you can reference this in any of the lifecycle methods (i.e: componentDidMount , componentDidUpdate etc) including the render function.

-You can only subscribe to a single context using this API. If you need to read more than one see Consuming Multiple Contexts.

import React from 'react';
import ThemeContext from './context';
class ThemedButton extends React.Component {

static contextType = ThemeContext;
render() {
return <Button theme={this.context} />;
}
}

Alright! I assume now you have a good idea about how we can Consume the Created Contexts inside any type of React Components, now Let’s look at a complex example where we can use multiple Context inside an Application.

Using Multiple Contexts

In order to showcase using multiple Contexts inside a React Application, let’s think of a scenario where we need to cater React components based on current user Authentication state and selected Language of the Application.

Steps:

1. Creating Contexts

Application Contexts file

2. Providing Contexts

App.js — Provide initial data to contexts

3. Consuming Contexts

Accessing Created Contexts

I hope now you have a solid understanding of the React Context API features. Also, I need to add one more thing if you are using React Dev Tools, there is one additional functionality given by the React Context API, thus you can give separate names to each of the Consumers you create, that way you can identify created consumers with the explicit name set by you in the React Dev tool.

Naming Consumers:

const MyNamedContext = React.createContext(/* initial value */);
MyNamedContext.displayName = 'MyDisplayName';
<MyNamedContext.Provider> // "MyDisplayName.Provider" in DevTools
<MyNamedContext.Consumer> // "MyDisplayName.Consumer" in DevTools

Context API FAQ

  1. What is the context in React?
    React’s context allows you to share information with any component, by storing it in a central place and allowing access to any component that requests it (usually you are only able to pass data from parent to child via props).
  2. What is a provider?
    The provider acts as a delivery service. When a consumer asks for something, it finds it in the context and delivers it to where it’s needed.
  3. Does the React Context API make Redux obsolete?
    The Context API makes one feature of Redux obsolete — the central store. If you don’t use any of Redux’s other features you can replace the whole library with this new native (to React) solution. In contrast, Redux provides a whole toolkit for managing state:
    - It comes with a time-traveling debugger
    - It provides a middleware API, giving you access to tools like redux-sagas
    - It's React bindings prevent many unnecessary renders
  4. Can I Replace Redux with Context API features?
    Well, that’s a tricky question to answer; If you’re only using Redux to avoid passing down props, context could replace Redux — but then you probably didn’t need Redux in the first place. Context also doesn’t give you anything like the Redux DevTools, the ability to trace your state updates, middleware to add centralized application logic, and other powerful capabilities that Redux enables.

I hope, I covered everything you need to understand about the React Context API and its usages, if you have any questions related to that, feel free to ask in the comment section below. Cheers!!

Versatile Full-stack Developer with 5+ years of experience designing, developing, and managing complex applications and internal frameworks.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store