React useContext Hook

Sharing data across components without prop drilling

🌐 What is useContext?

useContext is a React Hook that lets you read and subscribe to context from your component. It provides a way to share data globally across components without passing props through every level of the tree.


import { useContext } from 'react';

function Component() {
  const value = useContext(MyContext);
  return <div>{value}</div>;
}
                                    

useContext Key Concepts

🎯

Global State

Share data across components

const value = useContext(Context);
🚫

No Prop Drilling

Skip intermediate components

// Direct access to context
useContext(ThemeContext)
🔄

Auto Updates

Re-render when context changes

<Context.Provider value={state}>
📦

Multiple Contexts

Use different contexts together

const theme = useContext(ThemeContext);
const user = useContext(UserContext);

🔹 Creating and Using Context

To use context, you first create it with createContext, then provide a value with Provider, and finally consume it with useContext. This three-step process enables global state management.

import { createContext, useContext } from 'react';

// Step 1: Create context
const ThemeContext = createContext('light');

// Step 2: Provide context value
function App() {
  return (
    <ThemeContext.Provider value="dark">
      <Toolbar />
    </ThemeContext.Provider>
  );
}

// Step 3: Consume context
function Toolbar() {
  const theme = useContext(ThemeContext);
  return <div>Current theme: {theme}</div>;
}

Output:

Current theme: dark

🔹 Theme Switcher Example

A common use case for context is theme management. This example shows how to create a theme context that allows any component to access and change the current theme.

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

// Create theme context
const ThemeContext = createContext();

// Theme provider component
function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light');
  
  const toggleTheme = () => {
    setTheme(theme === 'light' ? 'dark' : 'light');
  };
  
  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

// Component using theme
function ThemedButton() {
  const { theme, toggleTheme } = useContext(ThemeContext);
  
  return (
    <button 
      onClick={toggleTheme}
      style={{
        background: theme === 'light' ? '#fff' : '#333',
        color: theme === 'light' ? '#000' : '#fff'
      }}
    >
      Toggle Theme (Current: {theme})
    </button>
  );
}

// App with provider
function App() {
  return (
    <ThemeProvider>
      <ThemedButton />
    </ThemeProvider>
  );
}

Output:

🔹 User Authentication Context

Context is perfect for managing user authentication state. This pattern allows any component to check if a user is logged in and access user information without prop drilling.

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

// Create auth context
const AuthContext = createContext();

// Auth provider
function AuthProvider({ children }) {
  const [user, setUser] = useState(null);
  
  const login = (username) => {
    setUser({ name: username });
  };
  
  const logout = () => {
    setUser(null);
  };
  
  return (
    <AuthContext.Provider value={{ user, login, logout }}>
      {children}
    </AuthContext.Provider>
  );
}

// Component using auth
function UserProfile() {
  const { user, login, logout } = useContext(AuthContext);
  
  if (!user) {
    return (
      <button onClick={() => login('John')}>
        Login
      </button>
    );
  }
  
  return (
    <div>
      <p>Welcome, {user.name}!</p>
      <button onClick={logout}>Logout</button>
    </div>
  );
}

Output (logged out):

🔹 Multiple Contexts

You can use multiple contexts in the same component to access different pieces of global state. Each context operates independently and can be updated separately.

import { createContext, useContext } from 'react';

const ThemeContext = createContext();
const UserContext = createContext();
const LanguageContext = createContext();

function Dashboard() {
  const theme = useContext(ThemeContext);
  const user = useContext(UserContext);
  const language = useContext(LanguageContext);
  
  return (
    <div>
      <p>Theme: {theme}</p>
      <p>User: {user.name}</p>
      <p>Language: {language}</p>
    </div>
  );
}

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <UserContext.Provider value={{ name: 'John' }}>
        <LanguageContext.Provider value="en">
          <Dashboard />
        </LanguageContext.Provider>
      </UserContext.Provider>
    </ThemeContext.Provider>
  );
}

Output:

Theme: dark

User: John

Language: en

🔹 Custom Context Hook

Creating a custom hook for your context makes it easier to use and provides better error handling. This pattern ensures the context is used within the correct provider.

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

const CartContext = createContext();

// Custom hook for cart context
function useCart() {
  const context = useContext(CartContext);
  if (!context) {
    throw new Error('useCart must be used within CartProvider');
  }
  return context;
}

// Cart provider
function CartProvider({ children }) {
  const [items, setItems] = useState([]);
  
  const addItem = (item) => {
    setItems([...items, item]);
  };
  
  return (
    <CartContext.Provider value={{ items, addItem }}>
      {children}
    </CartContext.Provider>
  );
}

// Component using custom hook
function ShoppingCart() {
  const { items, addItem } = useCart();
  
  return (
    <div>
      <p>Items in cart: {items.length}</p>
      <button onClick={() => addItem('Product')}>
        Add Item
      </button>
    </div>
  );
}

Output:

Items in cart: 0

🔹 useContext Best Practices

✅ Do's:

  • Create custom hooks: Wrap useContext in custom hooks
  • Split contexts: Use separate contexts for different concerns
  • Provide defaults: Set default values in createContext
  • Memoize values: Use useMemo for complex context values

❌ Don'ts:

  • Don't overuse: Not everything needs to be in context
  • Don't put everything in one context: Split by concern
  • Don't forget Provider: Always wrap with Provider
  • Don't use for frequent updates: Can cause performance issues

🧠 Test Your Knowledge

What problem does useContext solve?