React useContext Hook: Beginner’s Guide with Examples

In React, props are used to pass data from parent to child components. But in large applications, passing props through multiple levels can become cumbersome.

The useContext Hook allows you to:

  • Share data globally across multiple components

  • Avoid “prop drilling” (passing props through layers unnecessarily)

  • Make your app easier to maintain

Think of useContext as a global store for specific data, without the need for complex state management libraries.

How useContext Works

  1. Create a ContextReact.createContext()

  2. Provide the Context<Context.Provider> wraps components that need access

  3. Consume the ContextuseContext(MyContext) in child components

Example 1: Basic useContext

 Create Context

 
import React, { createContext } from "react";
export const ThemeContext = createContext();

 Provide Context

import { ThemeContext } from "./ThemeContext";

function App() {
  const theme = "dark";

  return (
    <ThemeContext.Provider value={theme}>
      <Toolbar />
    </ThemeContext.Provider>
  );
}

 Consume Context

import { useContext } from "react";
import { ThemeContext } from "./ThemeContext";

function Toolbar() {
  const theme = useContext(ThemeContext);
  return <h1>Current Theme: {theme}</h1>;
}

Output:

 
Current Theme: dark

Example 2: Sharing Objects with Context

const UserContext = React.createContext();

function App() {
  const user = { name: "John", age: 25 };

  return (
    <UserContext.Provider value={user}>
      <Profile />
    </UserContext.Provider>
  );
}

function Profile() {
  const user = useContext(UserContext);
  return (
    <div>
      <h2>Name: {user.name}</h2>
      <p>Age: {user.age}</p>
    </div>
  );
}
  • Context can store objects, arrays, or any value.

  • useContext gives direct access to the value without prop drilling.

Example 3: Nested Components

function App() {
  const language = "React";

  return (
    <LanguageContext.Provider value={language}>
      <Parent />
    </LanguageContext.Provider>
  );
}

function Parent() {
  return <Child />;
}

function Child() {
  const language = useContext(LanguageContext);
  return <h1>Learning: {language}</h1>;
}
  • Even if Child is nested deeply, it can directly consume the context.

  • Eliminates the need to pass props through Parent.

Best Practices for useContext

PracticeExplanation
Keep context focusedOne context per domain (e.g., ThemeContext, UserContext).
Avoid frequent updatesUpdating context often can cause performance issues.
Combine with useReducerFor complex state logic in global context.
Default valuesProvide meaningful default values for safety.
Do not abuseOnly use context for data that truly needs to be global.

FAQ

Q1: Can I update the context value?
 Yes, by storing the value in state (useState) and passing it to <Provider value={state}>.

Q2: Can I have multiple contexts?
 Yes! You can wrap components with multiple Providers.

Q3: Does useContext replace Redux?
Not fully. Context is best for small to medium apps. For large, complex global state, consider Redux or Zustand.