An Example: Use Context and Hooks to share state between different components
See the app in action on 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:
- We make a context called UsersContext
- We wrap the components within the Provider of this UsersContext.
- 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:
What is going on in this file
- We are using
createContext
function from React to create a new Context. A Context has aProvider
component and aConsumer
component. - We export the following three from this file:
- The Context
This will be used by other components through theuseContext
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 theuseState
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 Context
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:
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!
also you don’t need -export const { Consumer } = Context; <–delete this line
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.
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!
error:‘UsersContext’ is not exported ’ using this link of code
import { UsersContext } from “./context”;