React Context API is a feature that provides a way to pass data down through the component tree without needing to pass props manually between components. The value of React Context provided by one component can be accessed by other components by consuming the context.
The data you shared through Context API can be considered as “global” for a tree of React components. The Context API can be used to share the currently authenticated user, selected theme or preferred language.
Creating context is as simple as calling the React.createContext()
function and assign it into a variable. Just like useState
hook, you can put a default data into as the first argument of the function:
import React from 'react';
// defaults to 'en'
const LanguageContext = React.createContext('en')
Now we have the LanguageContext
available for use. This also gives you the LanguageContext.Provider
and LanguageContext.Consumer
component. Let’s learn how to provide data value into the context first.
Providing context
The value provided into context is usually obtained from state, so that when the state change, the context value also change. You need to wrap your React component with the Provider
component. Here’s an example:
import React from 'react'
const LanguageContext = React.createContext('en')
function App() {
const language = 'fr'
return (
<LanguageContext.Provider value={language}>
<Hello />
</LanguageContext.Provider>
)
}
Now both Hello
and all components under it can access the value of LanguageContext
. There are many ways to extract the value of a context depending on your component type (function or class). Let’s learn how to extract content value in function components first.
Consuming context in function components
Function components can grab the value of context by using the useContext
hook. The hook accepts a context object — which is returned by React.createContext()
— and returns the value of that context.
Here’s the example:
function Hello() {
const language = useContext(LanguageContext)
if (language === "fr") {
return <h1>Bonjour!</h1>
}
return <h1>Hello!</h1>
}
In most application requirements, you will need the context value to change over time. You can use the state to change the value of context like this:
import React, { useState, useContext } from "react"
const LanguageContext = React.createContext()
function App() {
const [language, setLanguage] = useState("en");
const changeLanguage = () => {
if (language === "en") {
setLanguage("fr")
} else {
setLanguage("en")
}
};
return (
<LanguageContext.Provider value={language}>
<Hello />
<button onClick={changeLanguage}>Change Language</button>
</LanguageContext.Provider>
)
}
Here’s a working Code Sandbox example. Instead of passing language down to Hello
component as prop
, you simply grab the context value and use it to conditionally render the output.
Consuming context in class components
In class components, you can get the value of context by using the Context.Consumer
component. The component requires a function as its child, because it will pass the current context value into it. You then need to return a React element to be rendered on the screen:
class Hello extends React.Component {
render() {
return (
<LanguageContext.Consumer>
{(language) => {
if (language === "fr") {
return <h1>Bonjour!</h1>;
}
return <h1>Hello!</h1>;
}}
</LanguageContext.Consumer>
);
}
}
I don’t know about you, but the Consumer
function pattern looks confusing to me! Fortunately, React team also feel the same way so they created another way to consume context in class components by using the contextType
property:
Hello.contextType = LanguageContext
By assigning contextType
to the context object, you can use this.context
to retrieve the context value. You can also assign the contextType
inside the class component as a static field. Here’s the full code:
class Hello extends React.Component {
static contextType = LanguageContext;
render() {
const language = this.context;
if (language === "fr") {
return <h1>Bonjour!</h1>;
}
return <h1>Hello!</h1>;
}
}
And here’s another Code Sandbox example for you to inspect.
Separating context from components
Because of the global nature of context API, you will pass its value into many components inside your application. It’s very common to have one provider and many consumers of the Context API as your project grows. As you’ve learned from previous sections, getting the value out of Context API requires you to reference the context object both in function and class components.
You need to organize and separate Context from component to make it more maintainable. Here’s an example project structure that you can follow when you need to use context API.