DEV Community

"Rocky" Hiroki Ueno
"Rocky" Hiroki Ueno

Posted on

Managing Global and Persistent State with Context API in React

Managing global state is an essential feature in many applications. It is commonly used for tasks like handling user login data or controlling the app’s theme.
Additionally, persisting state across page refreshes is crucial to ensure a consistent user experience.
In this article, I’ll demonstrate a simple approach to achieving global and persistent state management using the Context API, with a practical example of theme control.

Roadmap

Step 1: Create ThemeContext.tsx

In this file, we create the ThemeContext to manage theme-related state globally. We also define a custom hook, useThemeContext, to simplify access to the context in components.

import { createContext, useContext } from "react";

// Define context type
interface ThemeContextType {
  isDarkMode: boolean;
  toggleTheme: () => void;
}

// Create context
export const ThemeContext = createContext<ThemeContextType | undefined>(undefined);

// Create custom hook to access
export const useThemeContext = () => {
  const context = useContext(ThemeContext);
  if (!context) {
    throw new Error("useTheme must be used within a ThemeProvider");
  }
  return context;
};
Enter fullscreen mode Exit fullscreen mode

Step 2: Create ThemeProvider.tsx

The ThemeProvider component provides the ThemeContext to its children and handles theme state changes.

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

export const ThemeProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
  const [isDarkMode, setIsDarkMode] = useState(false);

  const toggleTheme = () => {
    const newTheme = !isDarkMode ? "dark" : "light";
    // Change state value
    setIsDarkMode(!isDarkMode);
    // Save value to local storage
    // Toggle "dark" class in html element
    localStorage.setItem("theme", newTheme);
    document.documentElement.classList.toggle("dark", !isDarkMode);
  };

  return (
    <ThemeContext.Provider value={{ isDarkMode, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
};
Enter fullscreen mode Exit fullscreen mode

Step 3: Wrap App in the ThemeProvider

Finally, wrap the App component with the ThemeProvider in main.tsx to enable context usage throughout the application.

import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import App from './App.tsx'
import { ThemeProvider } from './context/ThemeProvider.tsx'

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <ThemeProvider>
      <App />
    </ThemeProvider>
  </StrictMode>,
)
Enter fullscreen mode Exit fullscreen mode

Step 4: Access Context Values in Components

With the context set up, you can now access the theme values and toggle function in your components.

import { useThemeContext } from '@/context/ThemeContext';

function App() {
  const { isDarkMode, toggleTheme } = useThemeContext();

  return (
    <div>
      <p>isdarkMode: {isDarkMode}</p>
      <button onclick={toggleTheme}>Toggle Theme</button>
    </div>
  )
}

export default App
Enter fullscreen mode Exit fullscreen mode

Conclusion

This approach demonstrates how to manage global and persistent state using the Context API. You can now adapt this method for other use cases like user authentication or language settings.

Top comments (0)