JAVASCRIPT
Implement Global Theming (Light/Dark Mode) with useContext
A React hook pattern using `useContext` to manage and provide a global theme (like light/dark mode) across components, offering easy theme switching.
import React, { useState, useContext, createContext, useMemo, useCallback } from 'react';
// 1. Create a Context
const ThemeContext = createContext(null);
// 2. Create a Provider Component
export function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light'); // 'light' or 'dark'
const toggleTheme = useCallback(() => {
setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light'));
}, []);
// Memoize the value to prevent unnecessary re-renders of consumers
const contextValue = useMemo(() => ({
theme,
toggleTheme,
}), [theme, toggleTheme]);
return (
<ThemeContext.Provider value={contextValue}>
{children}
</ThemeContext.Provider>
);
}
// 3. Create a Custom Hook to consume the context
export function useTheme() {
const context = useContext(ThemeContext);
if (context === null) {
throw new Error('useTheme must be used within a ThemeProvider');
}
return context;
}
// Example Usage:
// import React from 'react';
// import { ThemeProvider, useTheme } from './useTheme'; // Assuming useTheme.js
// function ThemeSwitcher() {
// const { theme, toggleTheme } = useTheme();
// return (
// <button onClick={toggleTheme}>
// Switch to {theme === 'light' ? 'Dark' : 'Light'} Mode
// </button>
// );
// }
// function ThemedComponent() {
// const { theme } = useTheme();
// const style = {
// padding: '20px',
// margin: '10px',
// borderRadius: '8px',
// backgroundColor: theme === 'light' ? '#fff' : '#333',
// color: theme === 'light' ? '#333' : '#fff',
// border: `1px solid ${theme === 'light' ? '#ccc' : '#666'} `,
// };
// return (
// <div style={style}>
// This component uses the {theme} theme.
// </div>
// );
// }
// function AppContent() { // Renamed to avoid confusion with the main App
// const { theme } = useTheme(); // Access theme here
// return (
// <div style={{ padding: '20px', minHeight: '100vh', backgroundColor: theme === 'light' ? '#f0f2f5' : '#282c34', color: theme === 'light' ? '#333' : '#f0f2f5' }}>
// <h1>My Themed Application</h1>
// <ThemeSwitcher />
// <ThemedComponent />
// <ThemedComponent />
// </div>
// );
// }
// function App() {
// return (
// <ThemeProvider>
// <AppContent />
// </ThemeProvider>
// );
// }
// export default App;
How it works: This pattern demonstrates how to implement a global theming system using React's `useContext` hook. The `ThemeProvider` component wraps your application, managing the current `theme` state and providing it, along with a `toggleTheme` function, to any descendant components via the `ThemeContext`. The `useTheme` custom hook simplifies consuming this context, making it easy for components to access the theme and switch it, enabling dynamic UI changes across your application. `useMemo` is used to optimize the context value.