Codementor Events

An Example: Use Context and Hooks to share state between different components

Published Feb 23, 2019Last updated Aug 22, 2019

See the app in action on sandbox:

Sandbox

High level overview

By using Context we are sharing state between multiple components without explicitly passing a prop through every level of the tree. This example app here shows a recipe that you can use to keep such shared state in your application.

In a nutshell, we are doing the following:

  1. We make a context called UsersContext
  2. We wrap the components within the Provider of this UsersContext.
  3. Individual components make use of useContext hook to get the value from the context.

Note : There can be multiple contexts and also nested contexts. However, in this example we have only one Context to keep it simple to understand.

Details about this app

In the following sections I am going to highlight the important details from the Context file and also from some of the components:

The UsersContext

In the context we are keeping the following props:

  • users (array of all users)
  • selectedUser (object containing one selected user)
  • setSelectedUser (function to select a user)
  • addUser (function to add new user)

In this file we are creating a new context and exporting it. We are also exporting the Provider and the Consumer of this context:

UsersContext

What is going on in this file

  1. We are using createContext function from React to create a new Context. A Context has a Provider component and a Consumer component.
  2. We export the following three from this file:
    • The Context
      This will be used by other components through the useContext Hook
    • The Provider:
      • receives initial values as props.
      • uses the useState hooks to keep the values in state.read more about useState hooks
      • has default props (so that default values are stored in the state initially when no props are passed)
      • makes a usersContext object with values and functions that we need in the context. (note that it also contains functions to update state, which are returned from the useState Hook)
      • Finally, it returns the Context Provider wrapping the children and passes the userContext object as its value.
    • The Consumer
      A React component that subscribes to context changes. This lets you subscribe to a context within a function component.

The provider used within App.js

The App component, which is at the first level in our application, is wrapping all of its children under the UserContextProvider. This Provider is passed the initial users value as a prop. As seen above, the value passed in props becomes the initial value in the context.

Now all of the descendants of this Provider can make use of the useContext hook as explained below

All consumers that are descendants of a Provider will re-render whenever the Provider’s value prop changes.

Using the useContext hook

In the UsersList component, we get the context through the useContext hook:

// import the hook
import React, { useContext } from "react";

//Import the Context
import { UsersContext } from "./context";
.
.
.
// get the current value in UsersContext through the hook
const usersContext = useContext(UsersContext);
const { users, selectedUser, setSelectedUser } = usersContext;

After this, we can get all the properties of the UsersContext including the functions and we can display the users list.

Without the useContext hook

It is important to note that without the useContext hook, the descendant components of a Provider can use the Consumer component. The Consumer component makes use of the renderProp function.

import { Consumer } from "./context";
<Consumer>
  {usersContext => /* render something based on the context value */}
</Consumer>

Updating value in the context

The Context itself passes down the functions which could be called to update the context. In this example we call the function setSelectedUser to populate the selectedUser property in the Context.

// in UsersList Component
.
.
const usersContext = useContext(UsersContext);
const { users, selectedUser, setSelectedUser } = usersContext;
.
.
.
    // Within the returned JSX,
    <div onClick={() => setSelectedUser(user)}></div>
.
.

Remember that UsersContext component actually keeps selectedUser in the state (explained above)

Other components make use of useContext as well

Similarly, UserDetails and AddUser Components make use of the useContext hook in to display the selected user's details, and to add a new user, respectively.

Conclusion

Thank you for visiting.
I hope this example helps you understand about Context and useContext hook.

Further reading:

Read more about React Context
See other built-in hooks

Discover and read more posts from Sambhav Gore
get started
post comments4Replies
sree
4 years ago

This is an incomplete code with bugs!

change export const Context = createContext({}); to export const UsersContext = createContext();

and add to app- note- there is no UserContextProvider as you mentioned in article! in your code it is called Provider!

<Provider>
            <Component {...pageProps} />
</Provider>

also you don’t need -export const { Consumer } = Context; <–delete this line

Zheng
4 years ago

Excellent app example and elegant code! I wonder why I’ve never seen this awesome use case of storing shared state within the Provider component before, not even in the React docs.

The App component, which is at the first level in our application, is wrapping all of its children under the UserContextProvider.

I would suggest just adding the code snippet under this step for completeness, since you’ve added the code snippet for every other step. I know it’s just a one liner, but I still had to check the sandbox to make sure that there wasn’t anything special.

Also, in the sandbox, I see that you’ve renamed the Provider that you exported to UserContextProvider, which you then refer to in the quote above, but the article doesn’t show that you renamed it so this might confuse readers.

Thanks for this awesome example!

Furqan Riaz
4 years ago

error:‘UsersContext’ is not exported ’ using this link of code

import { UsersContext } from “./context”;

Show more replies