React Foundations·Components, state and data

Context and shared state

Share values across a tree with Context, but only for data that is genuinely global.

Intermediate 12 min read Lesson 4 of 300 Challenge included
What you will be able to do
  • Create a context and export a provider plus a custom hook.
  • Wrap only the subtree that actually needs the value.
  • Give consumers a clear default so a missing provider fails loudly.
  • Reach for a state library when the data is not really global.

In plain English

Context lets a component share a value with a whole subtree without passing props through every level. You create a context with createContext, wrap a tree in a provider that supplies the value, and read it with useContext. A custom hook wraps the context read so components do not import the context directly. Context is the wrong tool for values that change constantly or belong to only one small branch, because it re-renders every consumer.

Step by step

  1. 1Decide what single value the whole subtree needs.
  2. 2Create the context with a type and a null default.
  3. 3Build a provider that owns the state and passes it down.
  4. 4Export a custom hook that reads the context and throws without a provider.
ThemeContext.tsxTSX
import { createContext, useContext, useState, type ReactNode } from 'react'

type Theme = 'light' | 'dark'

type ThemeContextValue = {
  theme: Theme
  toggle: () => void
}

const ThemeContext = createContext<ThemeContextValue | null>(null)

export function ThemeProvider({ children }: { children: ReactNode }) {
  const [theme, setTheme] = useState<Theme>('light')

  function toggle() {
    setTheme((current) => (current === 'light' ? 'dark' : 'light'))
  }

  return <ThemeContext.Provider value={{ theme, toggle }}>{children}</ThemeContext.Provider>
}

export function useTheme(): ThemeContextValue {
  const value = useContext(ThemeContext)
  if (value === null) {
    throw new Error('useTheme must be used within a ThemeProvider')
  }
  return value
}

Common mistakes

  • Storing rapidly changing data in Context causes every consumer to re-render on each change.
  • Exporting the raw context object lets consumers read it without a provider and get a confusing null.
  • Using Context for a value a single component could own locally adds indirection with no benefit.
  • Putting unrelated values into one context means the whole tree re-renders whenever any of them changes.
Your turn

Add a useTheme hook

Medium

Create a context with a null default, a provider that supplies a theme, and a useTheme hook that throws when the provider is missing.

TSX · starter
import { createContext, useContext } from 'react'

const ThemeContext = createContext<string | null>(null)
Check your understanding before moving on.
Knowledge checkQuestion 1

When is Context the wrong tool?

Select an answer to continue
Study tools

Make it yours.

Keep a private note for this lesson, then turn the key ideas into flashcards you can revisit.

Sign in to save notes and flashcards.Both are private to your account and stay with your progress.
Sign in
Finished reading?

Lock in what you just learned.

Mark this lesson complete to save your place and move one step closer to the certificate.

Lesson 4 of 300 · 0% of course