#react #tutorial #advanced

Day 7: Context API & Global State

Day 7: Context & Global State

The Problem: Prop Drilling

Imagine you have a User object in your top-level App component. You want to display the user’s avatar in the Navbar -> UserMenu -> Avatar component. You have to pass the user prop through every single layer, even if the intermediate components don’t care about it. This is called Prop Drilling, and it makes code hard to maintain.

The Solution: Context

Context provides a way to pass data through the component tree without having to pass props down manually at every level. Think of it as ā€œteleportingā€ data.

Creating Context

  1. Create the Context:

    import { createContext } from 'react';
    
    // Defaults to null if no provider is found
    export const UserContext = createContext(null);
  2. Provide the Context: Wrap the part of the app that needs the data in a Provider.

    // App.jsx
    import { useState } from 'react';
    import { UserContext } from './UserContext';
    
    function App() {
      const [user, setUser] = useState({ name: 'Jack' });
    
      return (
        // Value is the data we want to share
        <UserContext.Provider value={user}>
          <Navbar />
          <MainContent />
        </UserContext.Provider>
      );
    }
  3. Consume the Context: Use the useContext hook to read the data in any child component.

    // Avatar.jsx
    import { useContext } from 'react';
    import { UserContext } from './UserContext';
    
    function Avatar() {
      const user = useContext(UserContext);
    
      return <img src={user.avatarUrl} alt={user.name} />;
    }

No more passing props through Navbar or UserMenu! Avatar just grabs what it needs directly.

When to use Context?

Don’t overuse it. Context makes components harder to reuse because they now depend on that context existing. Good Use Cases:

  • Theme (Dark/Light mode)
  • Authenticated User data
  • Language/Localization
  • Global Notification system

Custom Hooks + Context pattern

A common pattern is to create a custom provider and hook to encapsulate logic.

// ThemeContext.jsx
import { createContext, useContext, useState } from 'react';

const ThemeContext = createContext();

export function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light');
  
  const toggleTheme = () => {
    setTheme(curr => curr === 'light' ? 'dark' : 'light');
  };

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

// Custom hook helper
export function useTheme() {
  return useContext(ThemeContext);
}

Now in your app, you just do:

  1. Wrap App in <ThemeProvider>
  2. In any component: const { theme, toggleTheme } = useTheme();

Homework for Day 7:

  1. Implement the ThemeProvider logic above.
  2. Use it to toggle a ā€œDark Modeā€ class on your main <div>.
  3. Create a button deep in your component tree that toggles the theme.

Get your compass ready, Day 8 is all about Routing!