Using React Context

Now, let’s explore what React Context is. React describes context as:

“Context provides a way to pass data through the component tree without having to pass props down manually at every level.”

This is exactly what we need for global state management. You start with a top-level component that uses Context to store global state.

Then, anywhere within your component tree, you can access and/or make updates to this state. This is pretty much the basic idea behind global state managers like Redux.

Remember we had to pass down the handleAddItem and handleRemoveItem methods as props to child components? Let’s refactor this to be obtained from the Context without having to drill down the props.

Using React Context is pretty easy. It takes the following form. First, you create a Context with a call to React.createContext() . This takes an optional initial value as an argument.

Then, you need to provide the Context somewhere in your component tree, using Context.Provider , so that components below that will have access to it. Then, wherever you want to use the Context, use Context.Consumer which will have access to the value.

const MyContext = React.createContext(/* initialValue /*) <MyContext.Provider value={/* value*/}>

<MyContext.Consumer>

{ value => /* components can access the value object */ }

</MyContext.Consumer>

</MyContext.Provider>

A good explanation of React Context is available in the documentation.

Let’s start by creating a new Context for our to-dos in contexts/TodoContext.js .

Update the App component as follows, to provide the TodoContext to our component tree.

App.js

Next, we can use the TodoContext.Consumer within our child components and have access to the state value passed to TodoContext.Provider .

Items.js

You may notice that we are repeating the TodoContext.Consumer wrapper everywhere we need to consume the Context value. We can refactor this using the useContext() Hook and make it less verbose.

Updated Items.js to use useContext

At the moment, we are storing our global state in the App component. This is not a very desirable behavior, especially as our to-do state grows in complexity and it’s not exactly the responsibility of the App component to hold the global state.

So, let’s move it to our already created TodoContext .

contexts/TodoContext.js

We are exporting two functions here. One is a the TodoProvider component, which is actually a higher-order component, wrapping the TodoContext.Provider along with a state.

This becomes our global store and we need to update the App component as follows:

Our App.js is a lot more simplified and does not have todo logic in it.

The second export is simply a custom Hook, wrapping the useContext Hook which already has TodoContext passed into it. In Items.js , you need to import useTodoContext and replace:

const todoContext = useContext(TodoContext);

With:

const todoContext = useTodoContext();

That’s it! Now we pretty much have a neat global store built with React Context and Hooks.