TUTORIAL

React Hooks Part 5: Sharing State with useContext

useContext lets any component read shared state without threading props through every layer. This article covers createContext, Provider setup, and the patterns that keep context from becoming a performance trap.


SERIES

React Hooks: A Complete Guide

A four-part deep-dive into React Hooks — from managing state with useState to squeezing performance out of useCallback and useMemo. Each article is standalone yet builds on the previous, giving you both quick reference and progressive mastery.

Table of Contents

The prop drilling problem

Imagine a theme setting that five levels of nested components all need. Without context you'd pass it as a prop through every layer — even the ones that don't use it. That's prop drilling, and it makes refactoring painful.

useContext solves this by letting any component in the tree read a value directly from the nearest matching Provider above it.

Creating and providing a context

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

export const ThemeContext = createContext('light')  // 'light' is the default

Wrap the parts of your tree that need access inside a Provider:

JSX
import { useState } from 'react'
import { ThemeContext } from './ThemeContext'

function App() {
  const [theme, setTheme] = useState('light')

  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      <Layout />
    </ThemeContext.Provider>
  )
}

Any component inside <Layout /> — no matter how deeply nested — can read theme and setTheme.

Consuming with useContext

JSX
import { useContext } from 'react'
import { ThemeContext } from './ThemeContext'

function Header() {
  const { theme, setTheme } = useContext(ThemeContext)

  return (
    <header data-theme={theme}>
      <button onClick={() => setTheme(t => t === 'light' ? 'dark' : 'light')}>
        Toggle theme
      </button>
    </header>
  )
}

No props needed. The component reaches up to the nearest ThemeContext.Provider.

The pattern: context + custom hook

Wrap useContext in a custom hook so consumers don't import the raw context object:

JSX
// useTheme.js
import { useContext } from 'react'
import { ThemeContext } from './ThemeContext'

export function useTheme() {
  const ctx = useContext(ThemeContext)
  if (!ctx) throw new Error('useTheme must be used inside ThemeProvider')
  return ctx
}

// Usage — clean and self-documenting
const { theme, setTheme } = useTheme()

This also gives you a clear error if someone accidentally uses the hook outside the Provider.

Performance: context re-renders every consumer

When the context value changes, every component that calls useContext re-renders. For a large tree this matters.

Split contexts by update frequency

JSX
// Don't put fast-changing state and stable config in the same context
const UserContext  = createContext(null)  // changes rarely
const CartContext  = createContext(null)  // changes often

// Fast-changing consumers only re-render when CartContext changes

Memoize the value object

JSX
const value = useMemo(() => ({ theme, setTheme }), [theme])

return <ThemeContext.Provider value={value}>…</ThemeContext.Provider>

Without useMemo, the value object is a new reference every render, causing all consumers to re-render even when theme hasn't changed.

Context vs state management libraries

Context isn't a Redux replacement for all use cases. The rule of thumb:

Use case Tool
Theme, locale, user session Context
Frequently updated global state Zustand / Jotai / Redux
Server data, caching React Query / SWR

Context is perfect for "ambient" data that changes infrequently and needs to be read everywhere.

Key takeaways

  • createContextProvideruseContext: the three-step pattern.
  • Wrap useContext in a custom hook for cleaner APIs and better error messages.
  • Split contexts by update frequency to avoid unnecessary re-renders.
  • Memoize the Provider's value object when it contains objects or functions.

Was this article helpful?

w

webencher Editorial

Software engineers and technical writers with 10+ years of combined experience in algorithms, systems design, and web development. Every article is reviewed for accuracy, depth, and practical applicability.

More by this author →