Mastering Theme Switching in React with Context API: A Complete Guide

This article explains how to use React's Context API to implement elegant multi‑theme switching, avoid props drilling, manage multiple contexts, and apply memoization techniques to prevent unnecessary re‑renders, improving performance and maintainability.

Sohu Tech Products
Sohu Tech Products
Sohu Tech Products
Mastering Theme Switching in React with Context API: A Complete Guide

React Context API Overview

React Context API enables sharing global data across component trees without prop drilling. Ideal for theme settings, authentication state, and application configuration.

Theme Switching Example

Prop‑drilling approach leads to verbose code and unnecessary re‑renders. Example:

function App() {
  const theme = 'dark';
  return <Parent theme={theme} />;
}
function Parent({ theme }) {
  return <Child theme={theme} />;
}
function Child({ theme }) {
  return <Switch theme={theme} />;
}
function Switch({ theme }) {
  return <button style={{background: theme === 'dark' ? '#000' : '#fff'}}>
    Toggle Theme
  </button>;
}

Context solution:

// src/contexts/ThemeContext.js
import { createContext } from 'react';
export const themes = {
  light: { background: '#fff', text: '#000', current: 'light' },
  dark:  { background: '#000', text: '#fff', current: 'dark' }
};
export const ThemeContext = createContext(themes.light);
// src/App.js
import React, { useState } from 'react';
import { ThemeContext, themes } from './contexts/ThemeContext';
import Navbar from './components/Navbar';
import Switch from './components/Switch';

export default function App() {
  const [theme, setTheme] = useState(themes.light);
  const toggleTheme = () => setTheme(t => t === themes.light ? themes.dark : themes.light);

  return (
    <div className="App">
      <ThemeContext.Provider value={theme}>
        <Navbar />
        <Switch changeTheme={toggleTheme} />
      </ThemeContext.Provider>
    </div>
  );
}
// src/components/Switch.js
import React, { useContext } from 'react';
import { ThemeContext } from '../contexts/ThemeContext';

export default function Switch({ changeTheme }) {
  const theme = useContext(ThemeContext);
  return (
    <button
      style={{ backgroundColor: theme.background, color: theme.text }}
      onClick={changeTheme}
    >
      Toggle Theme: {theme.current}
    </button>
  );
}
// src/components/Navbar.js
import React, { useContext } from 'react';
import { ThemeContext } from '../contexts/ThemeContext';

export default function Navbar() {
  const theme = useContext(ThemeContext);
  return (
    <div style={{ backgroundColor: theme.background }}>
      <ul style={{ display: 'flex', gap: '20px' }}>
        <li style={{ color: theme.text }}>Home</li>
        <li style={{ color: theme.text }}>Square</li>
        <li style={{ color: theme.text }}>Profile</li>
      </ul>
    </div>
  );
}

Resulting UI shows light and dark modes.

Light mode
Light mode
Dark mode
Dark mode

Creating Multiple Contexts

Separate concerns by defining distinct contexts, e.g., ThemeContext and UserContext, to avoid unrelated re‑renders.

// src/contexts/UserContext.js
import { createContext } from 'react';
export const UserContext = createContext({ username: '', age: 0 });
// src/App.js (combined providers)
import React, { useState } from 'react';
import { ThemeContext, themes } from './contexts/ThemeContext';
import { UserContext } from './contexts/UserContext';
import Navbar from './components/Navbar';
import Switch from './components/Switch';

export default function App() {
  const [theme, setTheme] = useState(themes.light);
  const [user, setUser] = useState({ username: 'mario', age: 25 });
  const toggleTheme = () => setTheme(t => t === themes.light ? themes.dark : themes.light);

  return (
    <div className="App">
      <ThemeContext.Provider value={theme}>
        <UserContext.Provider value={user}>
          <Navbar />
          <Switch changeTheme={toggleTheme} />
        </UserContext.Provider>
      </ThemeContext.Provider>
    </div>
  );
}

Preventing Unnecessary Re‑renders

Even with React.memo, components that consume a context re‑render when the context value changes. Apply the following techniques:

1. Use Multiple Contexts

Separate state into different contexts so only components that depend on a specific context update.

2. Split Components and Memoize

Wrap sub‑components with React.memo and pass only needed values as props.

const Card = () => {
  const { theme } = useContext(AppContext);
  return (
    <div>
      <CardTitle theme={theme} />
      <CardDescription theme={theme} />
    </div>
  );
};

const CardTitle = React.memo(({ theme }) => (
  <h2 style={{ color: theme.text }}>2024 Paris Olympics</h2>
));

const CardDescription = React.memo(({ theme }) => (
  <p style={{ color: theme.text }}>2024 Paris Olympics is the 33rd Summer Games</p>
));

3. Memoize Expensive Rendering

Use useMemo to cache the rendered subtree when the dependent values (e.g., theme) do not change.

const Card = () => {
  const { theme } = useContext(AppContext);
  return useMemo(() => (
    <div>
      <CardTitle theme={theme} />
      <CardDescription theme={theme} />
    </div>
  ), [theme]);
};

These patterns reduce the render cost of context‑driven components, improving performance in large React applications.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Performance Optimizationfrontend developmentReactContext APITheme Switching
Sohu Tech Products
Written by

Sohu Tech Products

A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.