12. Managing State with Context API
The Problem: Prop Drilling
When you need to pass data through many nested components, props can become messy. This is called prop drilling — passing props through components that don't need them just to reach a deeper component.
What is the Context API?
The Context API lets us share state between components without passing props manually at every level. It's great for global values like themes, user data or app settings.
Creating Context
import { createContext } from 'react'
export const UserContext = createContext()Providing Context
Wrap components that need access to the shared state using a Context Provider.
import { useState } from 'react'
import { UserContext } from './UserContext'
function App() {
const [user, setUser] = useState({ name: 'Chika', loggedIn: true })
return (
<UserContext.Provider value={{ user, setUser }}>
<Dashboard />
</UserContext.Provider>
)
}
export default AppConsuming Context
Use the `useContext` hook to access context values inside a component.
import { useContext } from 'react'
import { UserContext } from './UserContext'
function Dashboard() {
const { user } = useContext(UserContext)
return <h2>Welcome, {user.name}</h2>
}Updating Context Values
function LoginButton() {
const { setUser } = useContext(UserContext)
return (
<button onClick={() => setUser({ name: 'Ada', loggedIn: true })}>
Login as Ada
</button>
)
}When to Use Context
- Sharing theme settings (light/dark mode)
- Managing authenticated user data
- Language or app settings
- Shopping cart data in e-commerce apps
Avoid using context for everything. For complex state logic, tools like Redux or Zustand may be better.
Mini Project Step
Create a `ThemeContext` to manage your project's light/dark mode globally. Replace local theme state by wrapping your app in a provider.
// ThemeContext.jsx
import { createContext, useState } from 'react'
export const ThemeContext = createContext()
export function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light')
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
)
}// main.jsx or App.jsx
import { ThemeProvider } from './ThemeContext'
function App() {
return (
<ThemeProvider>
<Header />
<Home />
</ThemeProvider>
)
}
export default App