The Context API is a React feature used to share data across many components without passing props manually through every level of the component tree. It is especially helpful when the same data is needed in multiple places.
This solves a problem called prop drilling. Prop drilling happens when you pass data from a parent to a deeply nested child through several intermediate components that do not actually need that data.
With context, a parent provider can make a value available to all components below it, and those components can read that value directly.
Context is useful for shared app-wide data, but it is not always the best tool for every kind of state. For very complex state logic, dedicated state libraries may be more appropriate.
Before using context, it helps to understand the problem it solves. Imagine that a top-level component has user data, and a deeply nested component needs that data. Without context, every component in the middle must receive and pass the prop, even if it does not use it.
function App() {
const user = { name: 'Asha' }
return <Page user={user} />
}
function Page({ user }) {
return <Layout user={user} />
}
function Layout({ user }) {
return <Sidebar user={user} />
}
function Sidebar({ user }) {
return <Profile user={user} />
}
function Profile({ user }) {
return <h2>Welcome, {user.name}</h2>
}
Only Profile actually needs the user, but the prop must be passed through Page, Layout, and Sidebar. Context removes that repeated passing.
Using context usually involves three steps:
createContext()useContext()import { createContext, useContext } from 'react'
const UserContext = createContext(null)
export function UserProvider({ children }) {
const user = { name: 'Asha', role: 'Admin' }
return (
<UserContext.Provider value={user}>
{children}
</UserContext.Provider>
)
}
export function useUser() {
return useContext(UserContext)
}
import { UserProvider, useUser } from './UserContext'
function Profile() {
const user = useUser()
return <h2>Welcome, {user.name}</h2>
}
function App() {
return (
<UserProvider>
<Profile />
</UserProvider>
)
}
One of the most common uses of context is theme management. Instead of passing the current theme and toggle function through many components, you can keep them in one provider.
import { createContext, useContext, useState } from 'react'
const ThemeContext = createContext(null)
export function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light')
const toggleTheme = () => {
setTheme((prevTheme) => prevTheme === 'light' ? 'dark' : 'light')
}
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
)
}
export function useTheme() {
return useContext(ThemeContext)
}
import { useTheme } from './ThemeContext'
function ThemeToggle() {
const { theme, toggleTheme } = useTheme()
return (
<button onClick={toggleTheme}>
Current theme: {theme}
</button>
)
}
Another common use is authentication. Many parts of an application need access to the current user, login state, and logout function. Context makes that possible without passing those values manually through every screen.
import { createContext, useContext, useState } from 'react'
const AuthContext = createContext(null)
export function AuthProvider({ children }) {
const [user, setUser] = useState(null)
const login = (email) => {
setUser({ name: 'Asha', email })
}
const logout = () => {
setUser(null)
}
return (
<AuthContext.Provider value={{ user, login, logout, isLoggedIn: !!user }}>
{children}
</AuthContext.Provider>
)
}
export function useAuth() {
const context = useContext(AuthContext)
if (!context) {
throw new Error('useAuth must be used inside AuthProvider')
}
return context
}
That custom hook pattern is very common. It keeps the consuming code cleaner and can enforce that the hook is only used inside its provider.
Applications often use more than one context. For example, a project may have a theme context, auth context, and cart context. Those providers can be nested.
function App() {
return (
<ThemeProvider>
<AuthProvider>
<CartProvider>
<MainLayout />
</CartProvider>
</AuthProvider>
</ThemeProvider>
)
}
useAuth or useTheme for cleaner usageThe Context API helps React applications share data across many components without prop drilling. It is especially useful for global concerns such as authentication, theme, language, and shared user preferences.
Once you understand createContext, providers, and useContext, you can simplify many component trees and make shared state easier to manage. Used carefully, context is one of the most practical built-in tools in React.
Explore 500+ free tutorials across 20+ languages and frameworks.