The useContext hook is a powerful tool in React that allows you to share values between components without having to explicitly pass props through every level of the component tree. This is especially useful for managing global states or theming in a React application. This chapter will explore the useContext hook in detail, covering everything from basic usage to advanced patterns, ensuring a comprehensive understanding of its capabilities.
The useContext
hook provides a way to consume a context value created with React.createContext
. Context provides a way to pass data through the component tree without having to pass props down manually at every level.
To use useContext
, you first need to create a context. Then, you can provide a value to the context and consume it in any component.
import React, { useContext, useState } from 'react';
// Create a context with a default value
const MyContext = React.createContext('Default Value');
function ChildComponent() {
const value = useContext(MyContext); // Consume the context value
return The context value is: {value};
}
function App() {
const [contextValue, setContextValue] = useState('Hello, World!');
return (
);
}
export default App;
MyContext
is created with a default value of 'Default Value'
.ChildComponent
uses useContext(MyContext)
to consume the context value.App
provides the context value using MyContext.Provider
.App
allows changing the context value.
The context value is: Hello, World!
Clicking the button changes the context value displayed in ChildComponent
.
The useContext
hook simplifies accessing context values, but it’s essential to understand how to properly provide and consume context in various scenarios.
You can nest context providers to manage different contexts independently.
import React, { useContext, useState } from 'react';
const ThemeContext = React.createContext('light');
const UserContext = React.createContext({ name: 'Guest' });
function ThemeComponent() {
const theme = useContext(ThemeContext);
return Current theme: {theme};
}
function UserComponent() {
const user = useContext(UserContext);
return User name: {user.name};
}
function App() {
const [theme, setTheme] = useState('light');
const [user, setUser] = useState({ name: 'Guest' });
return (
);
}
export default App;
ThemeContext
and UserContext
are created for managing theme and user state, respectively.ThemeComponent
and UserComponent
consume their respective context values.App
provides the context values and includes buttons to change the theme and user.
Current theme: light
User name: Guest
Clicking “Toggle Theme” changes the theme context, and clicking “Change User” updates the user context.
Creating custom hooks to use context can simplify the consumption of context values and logic.
import React, { createContext, useContext, useState } from 'react';
// Create contexts
const ThemeContext = createContext('light');
const UserContext = createContext({ name: 'Guest' });
// Custom hooks
const useTheme = () => useContext(ThemeContext);
const useUser = () => useContext(UserContext);
function ThemeComponent() {
const theme = useTheme();
return Current theme: {theme};
}
function UserComponent() {
const user = useUser();
return User name: {user.name};
}
function App() {
const [theme, setTheme] = useState('light');
const [user, setUser] = useState({ name: 'Guest' });
return (
);
}
export default App;
useTheme
and useUser
custom hooks simplify accessing ThemeContext
and UserContext
.ThemeComponent
and UserComponent
.Similar to the previous example, but the use of custom hooks makes the code cleaner and easier to maintain.
Context can be used for managing global state in an application.
import React, { createContext, useContext, useReducer } from 'react';
// Create a context and a reducer for updating the context
const AppContext = createContext();
const initialState = {
theme: 'light',
user: { name: 'Guest' },
};
const reducer = (state, action) => {
switch (action.type) {
case 'TOGGLE_THEME':
return {
...state,
theme: state.theme === 'light' ? 'dark' : 'light',
};
case 'SET_USER':
return {
...state,
user: action.payload,
};
default:
return state;
}
};
const useAppContext = () => useContext(AppContext);
function AppProvider({ children }) {
const [state, dispatch] = useReducer(reducer, initialState);
return (
{children}
);
}
function ThemeComponent() {
const { state, dispatch } = useAppContext();
return (
Current theme: {state.theme}
);
}
function UserComponent() {
const { state, dispatch } = useAppContext();
return (
User name: {state.user.name}
);
}
function App() {
return (
);
}
export default App;
AppContext
is created for global state management.reducer
function handles state updates based on dispatched actions.AppProvider
component provides the state and dispatch function.useAppContext
custom hook simplifies accessing the context.ThemeComponent
and UserComponent
dispatch actions to update the state.
Current theme: light
User name: Guest
Clicking “Toggle Theme” changes the theme, and clicking “Change User” updates the user name.
In this example, we’ll create a simple theming functionality using useContext
. We’ll have a toggle button that switches between light and dark themes, and components will dynamically update their styles based on the current theme.
// App.js
import React, { useContext, useState } from 'react';
import './App.css'; // Assume this file contains styles for light and dark themes
// Create a context for theme
const ThemeContext = React.createContext();
// Theme provider component
function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light'); // Default theme is light
const toggleTheme = () => {
setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light'));
};
return (
{children}
);
}
// Component that uses the theme
function ThemedComponent() {
const { theme } = useContext(ThemeContext);
return (
Themed Component
This component changes based on the theme.
);
}
// App component that renders the themed component and theme toggle button
function App() {
return (
);
}
// Toggle button component
function ThemeToggle() {
const { theme, toggleTheme } = useContext(ThemeContext);
return (
);
}
export default App;
/* App.css */
.light-theme {
background-color: #f0f0f0;
color: #333;
}
.dark-theme {
background-color: #333;
color: #f0f0f0;
}
theme
) and provide a function (toggleTheme
) to switch between themes.ThemeContext.Provider
) and manages the state (theme
) and logic (toggleTheme
).theme
from ThemeContext
using useContext
and applies corresponding styles based on the theme.ThemedComponent
and ThemeToggle
wrapped within ThemeProvider
.useContext
to access theme
and toggleTheme
from ThemeContext
to provide a button to switch themes.When you run this application, you’ll see a themed component and a button labeled “Switch to Dark Theme” or “Switch to Light Theme”. Clicking the button toggles the theme and updates the component’s background and text color accordingly.
In this example, we’ll simulate user authentication using useContext
. We’ll have a login form that updates the user’s authentication status globally, allowing other components to conditionally render based on the user’s authentication state.
// App.js
import React, { useState, useContext } from 'react';
// Create a context for user authentication
const AuthContext = React.createContext();
// Auth provider component
function AuthProvider({ children }) {
const [isLoggedIn, setIsLoggedIn] = useState(false);
const login = () => {
setIsLoggedIn(true);
};
const logout = () => {
setIsLoggedIn(false);
};
return (
{children}
);
}
// Component that uses user authentication state
function AuthComponent() {
const { isLoggedIn, login, logout } = useContext(AuthContext);
return (
{isLoggedIn ? (
Welcome! You are logged in.
) : (
Please login to continue.
)}
);
}
// App component that renders the authentication component and other components
function App() {
return (
Authentication Example
);
}
// Component that is protected by authentication
function ProtectedComponent() {
const { isLoggedIn } = useContext(AuthContext);
return (
{isLoggedIn ? (
This is protected content.
) : (
Login to see protected content.
)}
);
}
export default App;
isLoggedIn
) and provide functions (login
, logout
) to update the authentication state.AuthContext.Provider
) and manages the state (isLoggedIn
) and functions (login
, logout
) to handle user authentication.isLoggedIn
, login
, and logout
from AuthContext
using useContext
and conditionally renders content and a login/logout button.AuthComponent
and ProtectedComponent
wrapped within AuthProvider
.isLoggedIn
from AuthContext
using useContext
and conditionally renders protected content based on the user’s authentication status.When you run this application, you’ll see an authentication example with a login form and protected content. Clicking “Login” will change the state to logged in, allowing access to protected content. Clicking “Logout” will log the user out and restrict access to protected content.
The useContext hook is a versatile and powerful feature in React that enables you to manage state and other values across your component tree without prop drilling. This chapter covered the basics of useContext, how to provide and consume context values, and advanced patterns like custom hooks and global state management. By mastering useContext, you can create cleaner and more maintainable React applications.Happy coding !❤️