stackademic

The leading education platform for anyone with an interest in software development.

useContext

Share values across the component tree without prop drilling

Overview

Context provides a way to pass data through the tree without manually threading props. Create a context, wrap a subtree with a Provider, and consume values with useContext in any descendant.

Syntax / Usage

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

const ThemeContext = createContext('light')

function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light')
  const value = { theme, setTheme }

  return (
    <ThemeContext.Provider value={value}>
      {children}
    </ThemeContext.Provider>
  )
}

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

function Header() {
  const { theme, setTheme } = useTheme()
  return (
    <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
      Toggle {theme}
    </button>
  )
}

Examples

Auth context for current user:

const AuthContext = createContext(null)

function AuthProvider({ children }) {
  const [user, setUser] = useState(null)
  const login = async (email, password) => {
    const u = await api.login(email, password)
    setUser(u)
  }
  const logout = () => setUser(null)

  return (
    <AuthContext.Provider value={{ user, login, logout }}>
      {children}
    </AuthContext.Provider>
  )
}

Locale for i18n:

const LocaleContext = createContext('en')
// Provider at app root; consumers read locale for formatting

Common Mistakes

  • Putting frequently changing values in context—every consumer re-renders
  • Creating new object literals in Provider value each render—memoize the value
  • Using context for all state instead of local state or dedicated libraries
  • Forgetting a custom hook with null checks for safer consumption

See Also

use-state props components conditional-rendering