React useContext Hook

React Context provides a way to manage state globally across a component tree. It can be used in conjunction with the useState Hook to share state between deeply nested components more efficiently than using useState alone.



The Challenge

State should be managed by the highest parent component in the component hierarchy that needs access to the state.

To illustrate, consider a scenario where we have several nested components. The topmost component and the bottommost component both need access to the state.

Without Context, we would have to pass the state as “props” through every nested component, a process known as “prop drilling”.

Example

Passing “props” through nested components:

import { useState } from "react";
import ReactDOM from "react-dom/client";

function MainComponent() {
  const [user, setUser] = useState("Alex Johnson");

  return (
    <>
      <h1>{`Hello ${user}!`}</h1>
      <IntermediateComponent1 user={user} />
    </>
  );
}

function IntermediateComponent1({ user }) {
  return (
    <>
      <h1>Intermediate Component 1</h1>
      <IntermediateComponent2 user={user} />
    </>
  );
}

function IntermediateComponent2({ user }) {
  return (
    <>
      <h1>Intermediate Component 2</h1>
      <IntermediateComponent3 user={user} />
    </>
  );
}

function IntermediateComponent3({ user }) {
  return (
    <>
      <h1>Intermediate Component 3</h1>
      <FinalComponent user={user} />
    </>
  );
}

function FinalComponent({ user }) {
  return (
    <>
      <h1>Final Component</h1>
      <h2>{`Hello ${user} again!`}</h2>
    </>
  );
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<MainComponent />);

In this example, even though components 1-3 don’t need the state, they still have to pass it along to reach the final component.




The Solution

The solution is to create a Context.

Creating Context

To create a Context, import createContext and initialize it:

import { useState, createContext } from "react";
import ReactDOM from "react-dom/client";

const UserContext = createContext();

Next, use the Context Provider to wrap the components that need access to the state.

Context Provider

Wrap child components with the Context Provider and supply the state value:

function MainComponent() {
  const [user, setUser] = useState("Alex Johnson");

  return (
    <UserContext.Provider value={user}>
      <h1>{`Hello ${user}!`}</h1>
      <IntermediateComponent1 />
    </UserContext.Provider>
  );
}

Now, all components within this tree will have access to the user Context.

Using the useContext Hook

To access the Context in a child component, use the useContext Hook.

First, include useContext in your import statement:

import { useState, createContext, useContext } from "react";

Then access the user Context in any component:

function FinalComponent() {
  const user = useContext(UserContext);

  return (
    <>
      <h1>Final Component</h1>
      <h2>{`Hello ${user} again!`}</h2>
    </>
  );
}




Full Example

Example

A complete example using React Context:

import { useState, createContext, useContext } from "react";
import ReactDOM from "react-dom/client";

const UserContext = createContext();

function MainComponent() {
  const [user, setUser] = useState("Alex Johnson");

  return (
    <UserContext.Provider value={user}>
      <h1>{`Hello ${user}!`}</h1>
      <IntermediateComponent1 />
    </UserContext.Provider>
  );
}

function IntermediateComponent1() {
  return (
    <>
      <h1>Intermediate Component 1</h1>
      <IntermediateComponent2 />
    </>
  );
}

function IntermediateComponent2() {
  return (
    <>
      <h1>Intermediate Component 2</h1>
      <IntermediateComponent3 />
    </>
  );
}

function IntermediateComponent3() {
  return (
    <>
      <h1>Intermediate Component 3</h1>
      <FinalComponent />
    </>
  );
}

function FinalComponent() {
  const user = useContext(UserContext);

  return (
    <>
      <h1>Final Component</h1>
      <h2>{`Hello ${user} again!`}</h2>
    </>
  );
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<MainComponent />);
Scroll to Top