REACT useContext

The useContext hook in React provides a simple and efficient way to access values from a Context object within functional components. It eliminates the need for using a Consumer component and simplifies the process of passing data down the component tree.

When to Use useContext

  1. Global State Management: Sharing global data (e.g., theme, authentication status, or user preferences) across multiple components.
  2. Avoid Prop Drilling: When data needs to be passed through multiple levels of components, useContext provides a cleaner solution.
  3. Simplify Context Consumption: Access context directly in functional components without wrapping them in <Context.Consumer>.

Syntax

const value = useContext(MyContext);
  • MyContext: The context object created using React.createContext.
  • value: The current context value.

 

Basic Example: Theme Context

Step 1: Create a Context

import React, { createContext } from "react";

export const ThemeContext = createContext();

Step 2: Provide the Context

Wrap your components with the ThemeContext.Provider and pass a value.

import React, { useState } from "react";
import { ThemeContext } from "./ThemeContext";

function App() {
    const [theme, setTheme] = useState("light");

    return (
        <ThemeContext.Provider value={{ theme, setTheme }}>
            <ChildComponent />
        </ThemeContext.Provider>
    );
}

export default App;

Step 3: Consume the Context Using useContext

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

function ChildComponent() {
    const { theme, setTheme } = useContext(ThemeContext);

    return (
        <div style={{ 
                      background: theme === "light" 
                      ? "#fff" : "#333", color: theme === "light" ? "#000" : "#fff" 
              }}>
            <p>Current Theme: {theme}</p>
            <button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>Toggle Theme</button>
        </div>
    );
}

export default ChildComponent;

Another Example: Authentication Context

Step 1: Create Context

import React, { createContext } from "react";

export const AuthContext = createContext();

Step 2: Provide Authentication State

import React, { useState } from "react";
import { AuthContext } from "./AuthContext";

function App() {
    const [isAuthenticated, setIsAuthenticated] = useState(false);

    return (
        <AuthContext.Provider value={{ isAuthenticated, setIsAuthenticated }}>
            <Login />
        </AuthContext.Provider>
    );
}

export default App;

Step 3: Consume Authentication Context

import React, { useContext } from "react";
import { AuthContext } from "./AuthContext";

function Login() {
    const { isAuthenticated, setIsAuthenticated } = useContext(AuthContext);

    return (
        <div>
            <p>{isAuthenticated ? "Welcome, User!" : "Please Log In"}</p>
            <button onClick={() => setIsAuthenticated(!isAuthenticated)}>
                {isAuthenticated ? "Log Out" : "Log In"}
            </button>
        </div>
    );
}

export default Login;

useContext with Multiple Contexts

If your application uses multiple contexts, you can combine them like this:

import React, { useContext } from "react";
import { ThemeContext } from "./ThemeContext";
import { AuthContext } from "./AuthContext";

function Dashboard() {
    const { theme } = useContext(ThemeContext);
    const { isAuthenticated } = useContext(AuthContext);

    return (
        <div style={{ background: theme === "light" ? "#fff" : "#333", color: theme === "light" ? "#000" : "#fff" }}>
            {isAuthenticated ? <p>Welcome to the Dashboard</p> : <p>Please Log In</p>}
        </div>
    );
}

export default Dashboard;

Best Practices for useContext

  1. Avoid Overusing Context: Use context for truly global data. For other cases, pass props directly or use libraries like Redux/Zustand for complex state management.
  2. Optimize Performance:
    • Minimize re-renders by memoizing context values using React.useMemo.
    • Split contexts if multiple values change frequently and independently.
  3. Combine with Custom Hooks: Encapsulate useContext logic in a custom hook for better reusability and cleaner components.

Encapsulating useContext in a Custom Hook

import React, { createContext, useContext, useState } from "react";

const ThemeContext = createContext();

export const ThemeProvider = ({ children }) => {
    const [theme, setTheme] = useState("light");

    return <ThemeContext.Provider value={{ theme, setTheme }}>{children}</ThemeContext.Provider>;
};

export const useTheme = () => useContext(ThemeContext);

Usage:

import React from "react";
import { ThemeProvider, useTheme } from "./ThemeContext";

function ThemedComponent() {
    const { theme, setTheme } = useTheme();

    return (
        <div style={{ background: theme === "light" ? "#fff" : "#333", color: theme === "light" ? "#000" : "#fff" }}>
            <button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>Toggle Theme</button>
        </div>
    );
}

function App() {
    return (
        <ThemeProvider>
            <ThemedComponent />
        </ThemeProvider>
    );
}

export default App;

Key Advantages of useContext

  1. Simplifies the consumption of context values.
  2. Avoids the need for prop drilling.
  3. Makes code cleaner and easier to maintain.

useContext is a powerful tool for managing shared state, and when used appropriately, it can significantly enhance your application’s modularity and scalability