
Using React Context
Posted on
6 min read
•0 views
While developing a React app you might come across a situation where you need to share a value or state between components. If the state needs to be shared between two components and they have a direct parent-child relationship, we can pass the state from the parent to the child through props. Or if we want to share the state within multiple components we might look into something like Redux.
If the state to be shared isn’t complex, Redux might be overkill as it takes some effort to setup and use. For those cases we can use React Context.
What we will be building

We will build an app that fetches and displays users from JSONPlaceholder.
The app will be divided into three parts.
- Context - Used to share the state within the app.
- Controls - The component used to change the user.
- Display - The component used to display the User data.
The Context
The Context will share any value given to it to its direct descendants.
In our case, we will need to share four sets of data.
userId
- The state that holds the current User ID.setUserId
- The function that updates theuserId
state.user
- The state the holds the User data.isFetching
- The state that will be used to indicate if the app is currently in the middle of fetching a user so that the controls can be disabled.
To start, create the context
folder and in it create the UserContext.js
file.
import React from "react";
Next let’s create and export the context with some default values.
import React from "react";
export const UserContext = React.createContext({
userId: 1,
setUserId: null,
user: null,
isFetching: false,
});
After that we’ll declare a Context Provider which will expose the context to its child components.
import React from "react";
export const UserContext = React.createContext({
userId: 1,
setUserId: null,
user: null,
isFetching: false,
});
export const UserProvider = ({ children }) => {
return <UserContext.Provider>{children}</UserContext.Provider>;
};
Then let’s declare the userId
, user
and isFetching
states and pass them to the provider.
import React from "react";
export const UserContext = React.createContext({
userId: 1,
setUserId: null,
user: null,
isFetching: false,
});
export const UserProvider = ({ children }) => {
const [userId, setUserId] = React.useState(1);
const [user, setUser] = React.useState(null);
const [isFetching, setIsFetching] = React.useState(false);
return (
<UserContext.Provider value={{ userId, setUserId, user, isFetching }}>
{children}
</UserContext.Provider>
);
};
Now we’ll setup an effect to automatically update the user
state whenever the userId
state is changed.
import React from "react";
export const UserContext = React.createContext({
userId: 1,
setUserId: null,
user: null,
isFetching: false,
});
export const UserProvider = ({ children }) => {
const [userId, setUserId] = React.useState(1);
const [user, setUser] = React.useState(null);
const [isFetching, setIsFetching] = React.useState(false);
const fetchUser = async () => {
try {
setIsFetching(true);
const response = await fetch(
`https://jsonplaceholder.typicode.com/users/${userId}`
);
const responseJson = await response.json();
setUser(responseJson);
} catch (error) {
console.error("> Error fetching user: ", error);
} finally {
setIsFetching(false);
}
};
React.useEffect(() => {
fetchUser();
}, [userId]);
return (
<UserContext.Provider value={{ userId, setUserId, user, isFetching }}>
{children}
</UserContext.Provider>
);
};
The Display component
Next let’s create the Display
component. Create the components
folder and in it add the file Display.js
.
import React from "react";
const Display = () => {
return <div></div>;
};
export default Display;
Now we can get the user
state by from the UserContext
with the useContext
hook.
import React from "react";
import { UserContext } from "../context/UserContext";
const Display = () => {
const { user } = React.useContext(UserContext);
return <div></div>;
};
export default Display;
To finish off the Display
component, let’s display the User data in a table.
import React from "react";
import { UserContext } from "../context/UserContext";
const Display = () => {
const { user } = React.useContext(UserContext);
return (
<div>
<table>
<tbody>
<tr>
<td>ID: </td>
<td>{user?.id}</td>
</tr>
<tr>
<td>Name: </td>
<td>{user?.name}</td>
</tr>
<tr>
<td>Username: </td>
<td>{user?.username}</td>
</tr>
<tr>
<td>Email: </td>
<td>{user?.email}</td>
</tr>
</tbody>
</table>
</div>
);
};
export default Display;
The Controls component
The Controls
component is used to change the current userId
.
To start create the Controls.js
file in the components
folder.
import React from "react";
const Controls = () => {
return <div></div>;
};
export default Controls;
After that, we can get userId
, setUserId
and isFetching
from UserContext
.
import React from "react";
import { UserContext } from "../context/UserContext";
const Controls = () => {
const { userId, setUserId, isFetching } = React.useContext(UserContext);
return <div></div>;
};
export default Controls;
Next we can add two buttons to change the userId
.
import React from "react";
import { UserContext } from "../context/UserContext";
const Controls = () => {
const { userId, setUserId, isFetching } = React.useContext(UserContext);
return (
<div>
<button onClick={() => setUserId(userId - 1)}>previous</button>
<button onClick={() => setUserId(userId + 1)}>next</button>
</div>
);
};
export default Controls;
Finally we will add a check to the buttons to disable them if the app is already fetching a user or to stop userId
from being set to value less than 1 or more than 10.
import React from "react";
import { UserContext } from "../context/UserContext";
const Controls = () => {
const { userId, setUserId, isFetching } = React.useContext(UserContext);
return (
<div>
<button
onClick={() => setUserId(userId - 1)}
disabled={userId <= 1 || isFetching}
>
previous
</button>
<button
onClick={() => setUserId(userId + 1)}
disabled={userId >= 10 || isFetching}
>
next
</button>
</div>
);
};
export default Controls;
Bringing it all together
Now all that’s left to is to bring everything together in the root component.
import React from "react";
const App = () => {
return <div className="App"></div>;
};
export default App;
Then we should wrap the root div
in the UserProvider
to make the context available to all components.
import React from "react";
import { UserProvider } from "./context/UserContext";
const App = () => {
return (
<UserProvider>
<div className="App"></div>
</UserProvider>
);
};
export default App;
Finally add the Display
and Controls
components.
import React from "react";
import Display from "./components/Display";
import Controls from "./components/Controls";
import { UserProvider } from "./context/UserContext";
const App = () => {
return (
<UserProvider>
<div className="App">
<Display />
<Controls />
</div>
</UserProvider>
);
};
export default App;
Wrapping up
Below is a sample of the app we just built. If you think you missed something, feel free to check out the code.
If you found this post helpful please be sure to share it! 😊