REACT Lesson 17 – Context API | Dataplexa
LESSON 17

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>
  );
}
DataFlow Dashboard

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

The useContext 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>
  );
}
DataFlow Dashboard

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.
App Component
Provider
Header
Sidebar
1. Create Context
2. Wrap with Provider
3. Pass value prop
4. useContext in children
✓ Direct access to data

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>
  );
}
DataFlow Dashboard

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>
  );
}
DataFlow Dashboard

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.

Context transforms React apps from prop-drilling nightmares into clean, organized code. Your DataFlow dashboard can now share user data, theme settings, and global state without passing props through dozens of components. The key insight: Context broadcasts data. useContext receives it. Any component, anywhere in the tree, can tune into the broadcast. This makes complex UIs much simpler to manage. But don't overuse context. Start with props for local data. Use context when multiple distant components need the same information. This balance keeps your app maintainable and performant.

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.