How to Update useContext Hook in React

This article explains how to update the state managed by the useContext hook in React. By combining useContext with the useState hook, you can pass both the state variable and its updater function through a Context Provider, allowing any deeply nested child component to read and modify global state.


The Concept

By itself, the useContext hook is only used to read data from a React context. To make this data dynamic and updatable, you must pair the context with a state management hook like useState or useReducer.

The general workflow involves: 1. Creating a context. 2. Creating a Provider component that holds a useState hook. 3. Passing both the state and the state-setter function (or a custom handler) into the Provider’s value prop. 4. Consuming the context in a child component using useContext to trigger updates.


Step-by-Step Implementation

Step 1: Create the Context

First, initialize your context. It is best practice to define this in a separate file so it can be easily imported.

// ThemeContext.js
import { createContext } from 'react';

export const ThemeContext = createContext(null);

Step 2: Create the Provider with State

Next, create a provider component. Inside this component, define a state variable and an updater function. Pass them together as an object inside the value prop of the context provider.

// ThemeProvider.jsx
import { useState } from 'react';
import { ThemeContext } from './ThemeContext';

export function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light');

  const toggleTheme = () => {
    setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light'));
  };

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

Step 3: Wrap Your Application

Wrap the components that need access to this context with your custom ThemeProvider in your root file (such as App.js or main.js).

// App.jsx
import { ThemeProvider } from './ThemeProvider';
import ThemeButton from './ThemeButton';

export default function App() {
  return (
    <ThemeProvider>
      <div className="app-container">
        <h1>React Context Update Guide</h1>
        <ThemeButton />
      </div>
    </ThemeProvider>
  );
}

Step 4: Consume and Update the Context

Now, any child component nested inside the ThemeProvider can access both the current theme and the toggleTheme function using the useContext hook.

// ThemeButton.jsx
import { useContext } from 'react';
import { ThemeContext } from './ThemeContext';

export default function ThemeButton() {
  // Destructure the state and the updater function from the context
  const { theme, toggleTheme } = useContext(ThemeContext);

  return (
    <div style={{ 
      background: theme === 'light' ? '#fff' : '#333', 
      color: theme === 'light' ? '#000' : '#fff',
      padding: '20px' 
    }}>
      <p>The current theme is <strong>{theme}</strong></p>
      <button onClick={toggleTheme}>
        Toggle Theme
      </button>
    </div>
  );
}

When the button is clicked, it calls toggleTheme, which updates the state inside ThemeProvider. Because the state changes, the Provider re-renders, and all components consuming ThemeContext receive the updated theme value.