React
Context API
Share data across multiple components without prop drilling using React's built-in Context API
Picture this: your DataFlow dashboard needs the current user info everywhere. The header shows the user avatar. The sidebar displays permission-based menu items. The stats cards filter by user role. Without Context, you'd pass user data down through dozens of components. That's called prop drilling — passing props through components that don't even use them. Context solves this by creating a shared state container that any component can access directly. Think of Context like a broadcasting station. Instead of whispering a message person-by-person down a long chain, you broadcast it once and everyone tunes in.What is Context?
Context consists of two parts: a Provider that holds the data, and Consumers that read it. The Provider wraps your component tree. Any child component, no matter how deep, can consume the context data. Here's how you create context:// Create context for user data
import { createContext } from 'react';
const UserContext = createContext();
function DataFlowApp() {
const currentUser = {
name: 'Sarah Chen',
role: 'admin',
avatar: 'SC'
};
return (
<UserContext.Provider value={currentUser}>
<Header />
<Sidebar />
<StatsBar />
</UserContext.Provider>
);
}What just happened?
We created a UserContext and wrapped our components with its Provider. The context now holds user data, but the child components aren't accessing it yet. Try this: The next step shows how components consume this shared data.
useContext Hook
TheuseContext hook lets components read context data. Import the hook, pass in your context, and get the current value. No more prop drilling through multiple layers.
// Components consuming user context
import { useContext } from 'react';
function Header() {
const user = useContext(UserContext);
return (
<header>
<h1>DataFlow</h1>
<div>Welcome, {user.name}</div>
<div className="avatar">{user.avatar}</div>
</header>
);
}
function Sidebar() {
const user = useContext(UserContext);
return (
<nav>
<a href="/dashboard">Dashboard</a>
<a href="/analytics">Analytics</a>
{user.role === 'admin' && (
<a href="/admin">Admin Panel</a>
)}
</nav>
);
}What just happened?
Both Header and Sidebar now access user data directly from context using useContext. Notice the admin-only "Admin Panel" link appears because Sarah has admin role. Try this: Change the role to "user" and watch the admin link disappear.
Context Flow Diagram
Context follows a predictable pattern. The Provider sits high in your component tree. Child components use useContext to tap into the shared data. When context value changes, all consumers re-render automatically.Multiple Contexts
DataFlow needs different types of shared data. User info, theme settings, notification state. You can create multiple contexts and use them together. Each context handles one concern.// Multiple contexts for different data
const UserContext = createContext();
const ThemeContext = createContext();
const NotificationContext = createContext();
function DataFlowApp() {
const [user] = useState({ name: 'Sarah Chen', role: 'admin' });
const [theme] = useState({ mode: 'dark', accent: '#047857' });
const [notifications] = useState({ count: 3, unread: true });
return (
<UserContext.Provider value={user}>
<ThemeContext.Provider value={theme}>
<NotificationContext.Provider value={notifications}>
<Dashboard />
</NotificationContext.Provider>
</ThemeContext.Provider>
</UserContext.Provider>
);
}What just happened?
The Dashboard component consumes all three contexts simultaneously. User data, theme settings, and notifications all flow down independently. Each context can be updated separately without affecting the others. Try this: Notice how the theme accent color matches the first stats card.
Context with State Updates
Context becomes powerful when combined with state. Instead of just reading data, components can trigger updates that propagate throughout the app. Think of it as a mini state management system.// Context with updatable state
function DataFlowProvider({ children }) {
const [user, setUser] = useState({
name: 'Sarah Chen',
role: 'admin',
preferences: { theme: 'dark' }
});
const updateUserPreferences = (newPrefs) => {
setUser(prev => ({
...prev,
preferences: { ...prev.preferences, ...newPrefs }
}));
};
return (
<UserContext.Provider value={{
user,
updateUserPreferences
}}>
{children}
</UserContext.Provider>
);
}What just happened?
The context now provides both data and functions. When you click the theme toggle, it calls updateUserPreferences which updates the context state. All components consuming this context automatically re-render with the new theme. Try this: Click the toggle and watch the entire interface switch themes instantly.
Context Best Practices
Context is powerful but use it wisely. Don't replace all prop passing with context. Reserve it for truly global data that many components need. Too much context creates tight coupling and makes components hard to test.Good for Context
- User authentication data
- Theme and language settings
- Global app configuration
- Shopping cart contents
Better as Props
- Component-specific data
- Event handlers for single features
- Form field values
- Temporary UI state
Performance Tip
When context value changes, all consuming components re-render. Split frequently-changing data into separate contexts to minimize unnecessary renders. Netflix separates user profile context from video player state context for this reason.
Quiz
1. In DataFlow, when UserContext value updates, what happens to Header and Sidebar components that both use useContext(UserContext)?
2. What React function creates a new context that DataFlow components can share?
3. How can DataFlow handle both user data and theme settings as separate shared state?
Up Next: React Router
Navigate between different pages in your single-page application using React Router's declarative routing system.