React useContext Hook

React useContext Hook

React's useContext Hook provides a way to pass data deeply throughout the component tree without having to pass props down manually at every single level.

To understand why this is useful, we first need to understand the problem it solves: Prop Drilling.


The Problem: Prop Drilling

Imagine you have a state variable in a top-level component, and a deeply nested component needs access to that state. To get the data there, you have to pass it as a prop through every intermediate component, even if those middle components don't need the data themselves.

// Prop Drilling Example (Bad)
function App() {
  const [theme, setTheme] = useState("dark");
  return <Header theme={theme} />;
}

function Header({ theme }) { return <Navbar theme={theme} />; }

function Navbar({ theme }) { // Navbar doesn't use 'theme', but must pass it down return <ProfileButton theme={theme} />; }

function ProfileButton({ theme }) { return <button className={theme}>Profile</button>; }

This becomes extremely tedious and hard to maintain in large applications. The React Context API, accessed via the useContext Hook, solves this completely.


Using the Context API

Implementing Context in React takes three steps:

  1. Create the Context.
  2. Provide the Context to the component tree.
  3. Consume the Context anywhere in the tree using useContext.

1. Creating Context

First, you create a context using createContext(). This is usually done outside of a component or in a separate file so it can be exported and imported wherever needed.

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

// 1. Create the Context const ThemeContext = createContext();

2. Providing Context

Next, you wrap the components that need access to the data with a Context Provider (ThemeContext.Provider). You pass the data to a special prop called value.

function App() {
  const [theme, setTheme] = useState("dark");

return ( // 2. Provide the Context <ThemeContext.Provider value={theme}> <Header /> </ThemeContext.Provider> ); }

Notice how we no longer pass the theme prop to <Header />.

3. Consuming Context with useContext

Finally, in any component nested deeply inside the Provider, you can import the Context and pass it to the useContext Hook to instantly grab the value.

function Header() {
  return <Navbar />;
}

function Navbar() { return <ProfileButton />; }

function ProfileButton() { // 3. Consume the Context const currentTheme = useContext(ThemeContext);

return ( <button className={btn-${currentTheme}}> Profile (Theme: {currentTheme}) </button> ); }

No prop drilling required! ProfileButton immediately reached up and grabbed the theme value provided by App.


Best Practices

While Context is incredibly powerful, it shouldn't be used for everything.


Note: useContext always looks upwards in the component tree to find the nearest matching Context Provider. If no provider is found, it returns the default value passed to createContext().


Exercise

?

Which of the following is the correct syntax to consume a Context named UserContext?