Understanding the React Context API

With React 16.3 we now have access to a brand new context API. With React’s old context API, the official recommendation was for developers to avoid using it, but now the new context API is a first-class citizen.

While not meant as a replacement for state management libraries like Redux or MobX, the context API allows for an easy way to share global data between multiple components without having to pass it as props. It solves a common problem known as the prop-drilling problem where props would need to be passed down to multiple components in the tree to reach the component that needs it.

The new API is especially useful to provide data that’s needed by a high percentage of the components in the tree. Global preferences like the selected theme or selected locale option are two good examples.

In this post we’ll explain how to use the new context API in as few words as possible. We’ll create a simple Locale context that provides the language preference between English and French to components in the app. Note that it’s just meant as a simple example to demonstrate an app’s global preference, and for real i18n in React a more robust solution like i18next is more appropriate.

React.createContext

To create a new context, use React’s new createContext function:

export const LocaleContext = React.createContext('en');

Here we also pass-in a default value of ‘en’ to the context, but you can also omit this default value if you’d like.

The createContext function returns a Provider and a Consumer component.

Provider

The Provider component is used to wrap components in the tree that will need access to the value from the context. Here let’s create a LocaleProvider component that wraps our LocaleContext’s provider and offers a way to change the context’s locale value:

context/LocaleContext.js

import React from 'react';

export const LocaleContext = React.createContext();

class LocaleProvider extends React.Component {
  constructor(props) {
    super(props);

    this.changeLocale = () => {
      this.setState(state => {
        const newLocale = state.locale === 'en' ? 'fr' : 'en';
        return {
          locale: newLocale
        };
      });
    };

    this.state = {
      locale: 'en',
      changeLocale: this.changeLocale
    };
  }

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

export default LocaleProvider;

Notice how the LocaleProvider component is just a thin wrapper around our context’s Provider component. The value of the context is passed to the provider using the value prop and then we just render LocaleContext’s children.

We pass our component’s state as the context value and from there the locale value and the changeLocale method to change the value will be available.

Using the Provider

We can make use of our provider at the top level of our App component:

App.js

import React, { Component } from 'react';

import LocaleProvider from './context/LocaleContext';
import Greeting from './Greeting';
import ToggleLocale from './ToggleLocale';

class App extends Component {
  render() {
    return (
      <LocaleProvider>
        <Greeting />
        <ToggleLocale />
      </LocaleProvider>
    );
  }
}

export default App;

Consumer

Now all that’s left to do is access the values from the context using the Consumer component.

Our Greeting component looks like this:

Greeting.js

import React from 'react';

import { LocaleContext } from './context/LocaleContext';

export default () => {
  return (
    <LocaleContext.Consumer>
      {localeVal =>
        localeVal.locale === 'en' ? <h1>Welcome!</h1> : <h1>Bienvenue!</h1>
      }
    </LocaleContext.Consumer>
  );
};

And our ToggleLocale component looks like this:

ToggleLocale.js

import React from 'react';

import { LocaleContext } from './context/LocaleContext';

export default () => {
  return (
    <LocaleContext.Consumer>
      {localeVal => (
        <button onClick={localeVal.changeLocale}>Change language</button>
      )}
    </LocaleContext.Consumer>
  );
};

The Consumer component uses the render prop pattern and expects a function as its children prop that will receive the value from the context. We can then access the context’s values and call the methods that it makes available.

With this in place, we can toggle the app’s greeting message between Welcome and Bienvenue.


In our example, the Greeting and ToggleLocale components are direct children of the LocaleProvider component, but they could be at any depth down the component tree and they would still have access to the global context data as long as the context’s consumer component is used and that the provider is somewhere higher up the tree.

⚛️ With this you should be good to start using the new context API in your apps. For more information, you can also refer to the official docs.

  Tweet It

🕵 Search Results

🔎 Searching...

Sponsored by #native_company# — Learn More
#native_title# #native_desc#
#native_cta#