useContext Hook: Another Way to Share Data
Introduction​
useContext is a hook in React that allows components to share data between components in React. Context provides a way to share data between components without having to pass props down through every level of the component tree.
To understand why this is useful, let's consider a simple example. Suppose we have a component that needs to know the current user's name. We could pass the user's name as a prop to the component, but this would mean that we would have to pass the prop down through every level of the component tree, all the way to the component that needs it. This is known as prop drilling.
useContext solves this problem by allowing us to create a context object that contains the user's name. We can then use the useContext hook to access the user's name from any component in the application, without having to pass it down as a prop.
useContext is useful because it simplifies the process of accessing shared data and makes the code more efficient. It eliminates the need for prop drilling, which can become cumbersome and difficult to manage as the component tree grows larger and more complex.
By using useContext, components can access shared data directly from the context object, regardless of their position in the component tree. This makes it easier to manage and update the shared data.
How to use useContext​
- Initialize a context usingÂ
createContext(). - Create a component that uses the context value usingÂ
useContext(MyContext). - Create a parent component that provides the context value usingÂ
<MyContext.Provider>. - Render the component inside the parent component.
Example:
import { createContext, useContext } from "react";
// Create a context
const MyContext = createContext();
// Create a component that uses the context
function MyComponent() {
const value = useContext(MyContext);
return <div>{value}</div>;
}
// Create a parent component that provides the context value
function ParentComponent() {
return (
<MyContext.Provider value="Hello from context!">
<MyComponent />
</MyContext.Provider>
);
}
Changing the Context​
This example has several important components:
MyContext is a context that returns two things:
texta stringsetTexta function to change said string
MyContextProvider, a React component that provides its children with the MyContext context
MyComponent, a React component that displays the text from the MyContext context
Buttons, a React component that displays two buttons, which when clicked, sets the text in the MyContext context to different strings
- It does this by using
setTextwhich we defined before
useContext uses the closest context in the tree​
When you use useContext, React will look up the component tree to find the closest context provider and use the data from that context. This means that if you have multiple context providers in your app, useContext will use the data from the closest one in the tree.
When to use useContext​
You should use useContext when you have data or functionality that needs to be shared across multiple components in your application. By using a context, you can avoid the need to pass props down through multiple levels of components, which can make your code more concise and easier to manage.
useContext is particularly useful when you have a complex component hierarchy and need to share data or functionality between components that are not directly related. However, it's important to note that overusing context can make your code harder to understand and maintain, so it's important to use it judiciously and only when it makes sense for your specific use case.
Let’s take a look at an example of how useContext should NOT be used:
In this example, we have a Card component that takes the text from a context:
function Card() {
const text = useContext(TextContext);
return (
<div className="flex h-48 w-36 place-content-center place-items-center justify-center rounded border-2 border-solid border-slate-100 bg-sky-700 p-10 text-slate-100 ">
<p>{text}</p>
</div>
);
}
And in the App, we create two cards using two different contexts to pass in two different texts
function App() {
return (
<>
<div className="place flex h-full min-h-screen w-full flex-wrap items-center justify-center gap-5 bg-zinc-800">
<TextContextProvider defaultText="Hello">
<Card />
</TextContextProvider>
<TextContextProvider defaultText="World">
<Card />
</TextContextProvider>
</div>
</>
);
}
In this case, it would actually be better to rely on props, since text is a property that isn’t really global in context:
function Card({ text }) {
return (
<div className="flex h-48 w-36 place-content-center place-items-center justify-center rounded border-2 border-solid border-slate-100 bg-sky-700 p-10 text-slate-100 ">
<p>{text}</p>
</div>
}
function App() {
return (
<>
<div className="place flex h-full min-h-screen w-full flex-wrap items-center justify-center gap-5 bg-zinc-800">
<Card text="Hello" />
<Card text="World" />
</div>
</>
);
}
While it is a useful tool for data that is used on a wider scale, it is important not to overuse useContext as it might add unneeded complexity.
Example: A Page of Posts​
Important Parts​
PostsContext defines the context being used to display/change the posts, as well as a provider for this context.
- Found in
src/lib/store - Defines
postswhich contains all the posts - Defines
setPostswhich allows the changing of the posts
Posts maps all the posts in the context and display them in a PostCard component
- Extracts
postfrom the context usinguseContext - Found in
src/components
PostCard a component that displays the post, and allows the user to delete the post from the context
- Extracts
setPostsfrom the context usinguseContext - Uses
setPoststo remove the post from the context when the delete button is pressed
main.tsx has been changed to wrap App in a PostsProvider to allow for the internal components to use the context
Additional Resources​
To learn more about useContext please refer to the React Docs.