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
-
Create the Context:
import { createContext } from 'react'; // Defaults to null if no provider is found export const UserContext = createContext(null); -
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> ); } -
Consume the Context: Use the
useContexthook 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:
- Wrap App in
<ThemeProvider> - In any component:
const { theme, toggleTheme } = useTheme();
Homework for Day 7:
- Implement the ThemeProvider logic above.
- Use it to toggle a āDark Modeā class on your main
<div>. - Create a button deep in your component tree that toggles the theme.
Get your compass ready, Day 8 is all about Routing!