useContext

⭐ Interview Importance: MEDIUM
⏱️ Revision Time: 2 min

useContext

useContext is a React Hook that lets you read and subscribe to context from your component. Context provides a way to pass data through the component tree without having to pass props down manually at every level (“prop drilling”).

1. Create the Context

First, you need to create a Context object using createContext outside of your components.

import { createContext } from 'react';

// Create a Context object. The argument is the default value.
export const ThemeContext = createContext('light');

2. Provide the Context

Wrap the part of your component tree that needs the data with a Context Provider. Pass the data to the value prop.

import { ThemeContext } from './ThemeContext';

function App() {
  const [theme, setTheme] = useState('dark');

  return (
    // The Provider makes the 'theme' value available to all components inside it
    <ThemeContext.Provider value={theme}>
      <Page />
    </ThemeContext.Provider>
  );
}

3. Consume the Context using useContext

Any component inside the Provider can read the context value using the useContext hook, regardless of how deep it is in the component tree.

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

function Button() {
  // Read the current value of ThemeContext
  const theme = useContext(ThemeContext);
  
  return <button className={theme}>Click me</button>;
}

Updating Context

Context is often paired with state to make it interactive. You can pass a state setter function down through context alongside the state value.

// 1. Create context
const UserContext = createContext(null);

// 2. Provide state and setter
function App() {
  const [user, setUser] = useState(null);
  
  return (
    <UserContext.Provider value={{ user, setUser }}>
      <Dashboard />
    </UserContext.Provider>
  );
}

// 3. Consume and update
function LoginButton() {
  const { user, setUser } = useContext(UserContext);
  
  return (
    <button onClick={() => setUser({ name: 'Alice' })}>
      Log in
    </button>
  );
}

Performance Considerations

When a Context Provider receives a new value, every component that consumes that context via useContext will re-render.

If your context value is an object, and you create a new object on every render of the Provider (e.g., value={{ user, theme }}), it will force a re-render of all consumers every time the Provider’s parent renders, even if the actual data hasn’t changed. To optimize this, you can memoize the context value using useMemo.

Interview Questions

Q: What architectural problem does useContext solve?
A: It solves “Prop Drilling” by allowing you to broadcast data (like themes, user sessions, or localization) deep into the component tree without having to manually pass props down through every single intermediate component layer.

Q: Does useContext cause performance issues?
A: It can. Whenever the value provided by the Context Provider changes, every single component that consumes that context via useContext will unconditionally re-render, even if they only care about a tiny piece of the context data.