Improve Data Flow through React Context
28.02.2024
28.02.2024
In order to manage data between parent and child components, React offers us the possibility to share data as props. Props can only flow in one direction, from parent to children. When a state change occurs in the parent element, all components depending on the changed status will be re-rendered.
However, when we need to share data in a huge tree of components at different nesting levels or we need to share “global” data like localization or authentication, we need to go for a more consistent solution, like React Context. Context is a powerful tool that makes it possible to share data for all child components without explicitly passing props through children.
How do we declare a context?
Let’s imagine we want to declare a context for managing a logged in user, ignoring the authentication process for simplicity.
UserContext.tsx
import { createContext, useContext, useState } from "react";
const UserContext = createContext(defaultValue);
export const UserContextProvider = ({ children }) => {
const [user, setUser] = useState<User | undefined>(undefined);
const login = (userData) => setUser(userData); // Add user information
const logout = () => setUser(undefined); // Remove user information
return (
<UserContext.Provider value={{ user, login, logout }}>
{children}
</UserContext.Provider>
);
};
export const useUserContext = () => {
const context = useContext(UserContext);
if (context === null) {
throw new Error("useUserContext must be used within UserContextProvider");
}
return context;
};
The useUserContext hook highlights the main limitation of context: it is accessible and it has value only for components which are descendants of the Provider. Rendering the UserContextProvider in the app.tsx will make our context globally available.
app.tsx
const App = (props: AppProps) => {
const { Component, pageProps } = props;
return (
<UserContextProvider>
<Component {...pageProps} />
</UserContextProvider>
);
};
MyComponent.tsx
const MyComponent = () => {
const { login, logout, user } = useUserContext();
return (
<>
<h4>{user
? `Welcome ${user.name} ${user.surname}!`
: "Please login!"}
</h4>
<Button
onClick={() => login({ name: "Super", surname: "Admin" })}>
Login
</Button>
<Button onClick={() => logout()}>Logout</Button>
</>
);
};
It’s now very simple to provide data to child components, no matter how deep they are in the components tree. The solution is just creating, providing and consuming a context!
Improve Data Flow through React Context
28.02.2024
Play with the WBS
13.09.2023
Zentralisierung von Application Logs
12.05.2023
A gentle introduction to JSON Web Tokens
30.03.2023