JAVASCRIPT

Persisting State with useLocalStorage Custom Hook

Build a `useLocalStorage` custom hook in React to automatically synchronize and persist component state with the browser's local storage.

import React, { useState, useEffect } from 'react';

// Custom hook for persisting state to local storage
function useLocalStorage(key, initialValue) {
  // State to store our value
  // Pass initial state function to useState so logic is only executed once
  const [storedValue, setStoredValue] = useState(() => {
    try {
      if (typeof window === 'undefined') {
        return initialValue;
      }
      // Get from local storage by key
      const item = window.localStorage.getItem(key);
      // Parse stored json or if none return initialValue
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      // If error also return initialValue
      console.warn(`Error reading localStorage key “${key}”:`, error);
      return initialValue;
    }
  });

  // useEffect to update local storage when the state changes
  useEffect(() => {
    try {
      if (typeof window !== 'undefined') {
        window.localStorage.setItem(key, JSON.stringify(storedValue));
      }
    } catch (error) {
      console.warn(`Error setting localStorage key “${key}”:`, error);
    }
  }, [key, storedValue]); // Only re-run if key or storedValue changes

  return [storedValue, setStoredValue];
}

function ThemeToggler() {
  const [theme, setTheme] = useLocalStorage('app-theme', 'light');

  const toggleTheme = () => {
    setTheme(prevTheme => (prevTheme === 'light' ? 'dark' : 'light'));
  };

  return (
    <div style={{ backgroundColor: theme === 'dark' ? '#333' : '#f0f0f0', color: theme === 'dark' ? '#f0f0f0' : '#333', padding: '20px', minHeight: '100vh' }}>
      <h1>Current Theme: {theme.toUpperCase()}</h1>
      <button onClick={toggleTheme}>Toggle Theme</button>
      <p>This theme preference is saved in local storage and persists across refreshes.</p>
    </div>
  );
}

export default ThemeToggler;
How it works: The `useLocalStorage` custom hook acts like `useState` but also synchronizes the state with the browser's `localStorage`. It attempts to retrieve the value from `localStorage` on initial render; if not found, it uses a provided initial value. Any subsequent updates to the state through the returned `setStoredValue` function will automatically update `localStorage`, ensuring data persistence across page refreshes.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs