useContext & the Context API

The Context API lets a component broadcast a value to all of its descendants without passing props through every layer in between. You create a context, wrap a subtree in a Provider that supplies the value, and any descendant reads it with useContext . It's the cure for prop drilling — and the standard way to share global data like theme, the current user, or language.

Learn useContext & the Context API in our free React course — a beginner-friendly interactive lesson with runnable examples, a practice exercise and a quick…

Part of the free React course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

1️⃣ The Problem: Prop Drilling

When a deeply nested component needs a value, you normally pass it as a prop — but that means every component in between has to accept and forward it, even though they never use it. That's prop drilling : tedious, noisy, and easy to break.

2️⃣ The Fix: createContext + Provider + useContext

Context has three parts. createContext makes the context object. A Provider wraps a subtree and supplies the value . Any descendant calls useContext to read it — no forwarding required.

Your turn — read a user out of a context and greet them:

3️⃣ The Nearest Provider Wins

When providers are nested, useContext reads the closest one above the consumer. That lets you override a context for just one part of the tree — for example, a "dark" section inside an otherwise "light" app.

These lines set up and consume a context. Put them in the right order:

📋 Quick Reference

createContext , {' '} , and useContext(Ctx) .

2. A consumer is nested under two providers (outer "light", inner "dark"). What does it read?

3. A consumer reads the default value even though you added a Provider. Likely cause?

The consumer isn't actually rendered inside that Provider's subtree.

Read a theme out of a context object and return the matching label, then change the theme and re-read. Run it and check your output.

Practice quiz

What problem does the Context API primarily solve?

  • Slow rendering of large lists
  • Fetching data from a server
  • Prop drilling — passing props through layers that don't use them
  • Memoizing expensive calculations

Answer: Prop drilling — passing props through layers that don't use them. Context lets a provider broadcast a value so any descendant can read it directly, avoiding threading the same prop through every layer.

What are the three pieces of the Context API?

  • createContext, a Provider, and useContext
  • useState, useEffect, useRef
  • connect, mapState, dispatch
  • subscribe, getSnapshot, getServerSnapshot

Answer: createContext, a Provider, and useContext. createContext makes the context object, <Ctx.Provider value={...}> supplies the value, and useContext(Ctx) reads it in any descendant.

How does a descendant component read a context value?

  • By importing it directly from the file
  • By receiving it as a prop from its parent
  • By calling createContext again
  • By calling useContext(MyContext)

Answer: By calling useContext(MyContext). A descendant calls useContext(MyContext) to read the nearest provider's value — no prop forwarding required.

When providers are nested, which value does useContext read?

  • The outermost provider's value
  • The nearest (closest) provider above the consumer
  • A merged combination of all providers
  • The default passed to createContext

Answer: The nearest (closest) provider above the consumer. useContext reads the closest provider above it in the tree, so an inner provider can override the outer one for just that subtree.

What does the argument to createContext (e.g. createContext('light')) specify?

  • The default value used when no matching Provider is found above
  • The provider's value for the whole app
  • The component that will consume it
  • A required initial state

Answer: The default value used when no matching Provider is found above. That argument is the default value, used only when a consumer has no matching Provider above it in the tree.

Why might all consumers re-render every time the parent renders?

  • Context always re-renders everything
  • useContext is called too many times
  • The Provider's value is a new object created on each render
  • The default value is missing

Answer: The Provider's value is a new object created on each render. Every consumer re-renders when the provider value changes by identity. Passing a fresh object each render triggers needless re-renders; memoize it with useMemo.

A consumer reads the default value even though you added a Provider. Likely cause?

  • The default value was set too high
  • The consumer isn't actually rendered inside that Provider's subtree
  • useContext was called at the top level
  • createContext was called twice

Answer: The consumer isn't actually rendered inside that Provider's subtree. If the consumer is not a descendant of the Provider, useContext falls back to the default value passed to createContext.

When is a plain prop better than Context?

  • When sharing the current theme app-wide
  • When sharing the logged-in user everywhere
  • When the value changes very rarely
  • When passing data down just one or two levels

Answer: When passing data down just one or two levels. For one or two levels, a normal prop is simpler and easier to trace. Context shines for truly global data like theme, user, or language.

How can you avoid unnecessary re-renders from a context Provider's value?

  • Call createContext inside the render
  • Wrap the value in useMemo so its reference only changes when needed
  • Remove the value prop
  • Use useLayoutEffect instead

Answer: Wrap the value in useMemo so its reference only changes when needed. Memoizing the value with useMemo keeps the same reference across renders unless its dependencies change, preventing consumers from re-rendering needlessly.

What happens if you write <Ctx.Provider> without a value prop?

  • It throws an error immediately
  • Consumers receive the default from createContext
  • Consumers receive undefined as the value
  • It uses the previous render's value

Answer: Consumers receive undefined as the value. A Provider without a value prop supplies undefined to its consumers, which is a common source of bugs. Always pass value.