useContext

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.

Understanding useContext

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.

Basic Usage

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 <div>The context value is: {value}</div>;
}

function App() {
  const [contextValue, setContextValue] = useState('Hello, World!');

  return (
    <MyContext.Provider value={contextValue}>
      <ChildComponent />
      <button onClick={() => setContextValue('New Value')}>
        Change Context Value
      </button>
    </MyContext.Provider>
  );
}

export default App;

				
			

Explanation:

  • 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.
  • A button in App allows changing the context value.
				
					<div>The context value is: Hello, World!</div>
<button>Change Context Value</button>

				
			

Clicking the button changes the context value displayed in ChildComponent.

Providing and Consuming Context

The useContext hook simplifies accessing context values, but it’s essential to understand how to properly provide and consume context in various scenarios.

Nested Context Providers

You can nest context providers to manage different contexts independently.

Example: Nested Context Providers

				
					import React, { useContext, useState } from 'react';

const ThemeContext = React.createContext('light');
const UserContext = React.createContext({ name: 'Guest' });

function ThemeComponent() {
  const theme = useContext(ThemeContext);
  return <div>Current theme: {theme}</div>;
}

function UserComponent() {
  const user = useContext(UserContext);
  return <div>User name: {user.name}</div>;
}

function App() {
  const [theme, setTheme] = useState('light');
  const [user, setUser] = useState({ name: 'Guest' });

  return (
    <ThemeContext.Provider value={theme}>
      <UserContext.Provider value={user}>
        <ThemeComponent />
        <UserComponent />
        <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
          Toggle Theme
        </button>
        <button onClick={() => setUser({ name: 'John Doe' })}>
          Change User
        </button>
      </UserContext.Provider>
    </ThemeContext.Provider>
  );
}

export default App;

				
			

Explanation:

  • 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.
				
					<div>Current theme: light</div>
<div>User name: Guest</div>
<button>Toggle Theme</button>
<button>Change User</button>

				
			

Clicking “Toggle Theme” changes the theme context, and clicking “Change User” updates the user context.

Advanced Usage

Context with Custom Hooks

Creating custom hooks to use context can simplify the consumption of context values and logic.

Example: Custom Hook for Context

				
					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 <div>Current theme: {theme}</div>;
}

function UserComponent() {
  const user = useUser();
  return <div>User name: {user.name}</div>;
}

function App() {
  const [theme, setTheme] = useState('light');
  const [user, setUser] = useState({ name: 'Guest' });

  return (
    <ThemeContext.Provider value={theme}>
      <UserContext.Provider value={user}>
        <ThemeComponent />
        <UserComponent />
        <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
          Toggle Theme
        </button>
        <button onClick={() => setUser({ name: 'John Doe' })}>
          Change User
        </button>
      </UserContext.Provider>
    </ThemeContext.Provider>
  );
}

export default App;

				
			

Explanation:

  • useTheme and useUser custom hooks simplify accessing ThemeContext and UserContext.
  • These hooks are used in ThemeComponent and UserComponent.

Output:

Similar to the previous example, but the use of custom hooks makes the code cleaner and easier to maintain.

Context for Global State Management

Context can be used for managing global state in an application.

Example: Global State Management

				
					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 (
    <AppContext.Provider value={{ state, dispatch }}>
      {children}
    </AppContext.Provider>
  );
}

function ThemeComponent() {
  const { state, dispatch } = useAppContext();
  return (
    <div>
      Current theme: {state.theme}
      <button onClick={() => dispatch({ type: 'TOGGLE_THEME' })}>
        Toggle Theme
      </button>
    </div>
  );
}

function UserComponent() {
  const { state, dispatch } = useAppContext();
  return (
    <div>
      User name: {state.user.name}
      <button onClick={() => dispatch({ type: 'SET_USER', payload: { name: 'John Doe' } })}>
        Change User
      </button>
    </div>
  );
}

function App() {
  return (
    <AppProvider>
      <ThemeComponent />
      <UserComponent />
    </AppProvider>
  );
}

export default App;

				
			

Explanation:

  • 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.
				
					<div>
  Current theme: light
  <button>Toggle Theme</button>
</div>
<div>
  User name: Guest
  <button>Change User</button>
</div>

				
			

Clicking “Toggle Theme” changes the theme, and clicking “Change User” updates the user name.

Example : Theming with useContext

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 (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

// Component that uses the theme
function ThemedComponent() {
  const { theme } = useContext(ThemeContext);

  return (
    <div className={`App ${theme === 'light' ? 'light-theme' : 'dark-theme'}`}>
      <h1>Themed Component</h1>
      <p>This component changes based on the theme.</p>
    </div>
  );
}

// App component that renders the themed component and theme toggle button
function App() {
  return (
    <ThemeProvider>
      <div className="App">
        <ThemedComponent />
        <ThemeToggle />
      </div>
    </ThemeProvider>
  );
}

// Toggle button component
function ThemeToggle() {
  const { theme, toggleTheme } = useContext(ThemeContext);

  return (
    <button onClick={toggleTheme}>
      Switch to {theme === 'light' ? 'Dark' : 'Light'} Theme
    </button>
  );
}

export default App;

				
			
				
					/* App.css */
.light-theme {
  background-color: #f0f0f0;
  color: #333;
}

.dark-theme {
  background-color: #333;
  color: #f0f0f0;
}

				
			

Explanation:

  • ThemeContext: Context created to manage the theme state (theme) and provide a function (toggleTheme) to switch between themes.
  • ThemeProvider: Wraps the application with the context provider (ThemeContext.Provider) and manages the state (theme) and logic (toggleTheme).
  • ThemedComponent: Consumes the theme from ThemeContext using useContext and applies corresponding styles based on the theme.
  • App: Renders ThemedComponent and ThemeToggle wrapped within ThemeProvider.
  • ThemeToggle: Uses useContext to access theme and toggleTheme from ThemeContext to provide a button to switch themes.

Output:

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.

Example : User Authentication with useContext

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 (
    <AuthContext.Provider value={{ isLoggedIn, login, logout }}>
      {children}
    </AuthContext.Provider>
  );
}

// Component that uses user authentication state
function AuthComponent() {
  const { isLoggedIn, login, logout } = useContext(AuthContext);

  return (
    <div>
      {isLoggedIn ? (
        <p>Welcome! You are logged in.</p>
      ) : (
        <p>Please login to continue.</p>
      )}
      <button onClick={isLoggedIn ? logout : login}>
        {isLoggedIn ? 'Logout' : 'Login'}
      </button>
    </div>
  );
}

// App component that renders the authentication component and other components
function App() {
  return (
    <AuthProvider>
      <div className="App">
        <h1>Authentication Example</h1>
        <AuthComponent />
        <ProtectedComponent />
      </div>
    </AuthProvider>
  );
}

// Component that is protected by authentication
function ProtectedComponent() {
  const { isLoggedIn } = useContext(AuthContext);

  return (
    <div>
      {isLoggedIn ? (
        <p>This is protected content.</p>
      ) : (
        <p>Login to see protected content.</p>
      )}
    </div>
  );
}

export default App;

				
			

Explanation:

  • AuthContext: Context created to manage user authentication state (isLoggedIn) and provide functions (login, logout) to update the authentication state.
  • AuthProvider: Wraps the application with the context provider (AuthContext.Provider) and manages the state (isLoggedIn) and functions (login, logout) to handle user authentication.
  • AuthComponent: Consumes isLoggedIn, login, and logout from AuthContext using useContext and conditionally renders content and a login/logout button.
  • App: Renders AuthComponent and ProtectedComponent wrapped within AuthProvider.
  • ProtectedComponent: Consumes isLoggedIn from AuthContext using useContext and conditionally renders protected content based on the user’s authentication status.

Output:

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 !❤️

Table of Contents

Contact here

Copyright © 2025 Diginode

Made with ❤️ in India