JAVASCRIPT

Persisting React State with `useLocalStorage` Custom Hook

Build a `useLocalStorage` custom hook to automatically synchronize a React component's state with the browser's local storage, preserving data across sessions.

import { useState, useEffect } from 'react';

/**
 * Custom hook to manage state that persists in localStorage.
 * @param {string} key The key for localStorage.
 * @param {any} initialValue The initial value for the state.
 * @returns {[any, Function]} A tuple containing the state value and its setter.
 */
export 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 {
      const item = window.localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      console.error(error);
      return initialValue;
    }
  });

  // useEffect to update localStorage when the state changes
  useEffect(() => {
    try {
      window.localStorage.setItem(key, JSON.stringify(storedValue));
    } catch (error) {
      console.error(error);
    }
  }, [key, storedValue]); // Only re-run if key or storedValue changes

  return [storedValue, setStoredValue];
}

// Example Usage:
// function UserSettings() {
//   const [theme, setTheme] = useLocalStorage('appTheme', 'light');
//   const [username, setUsername] = useLocalStorage('userName', '');

//   return (
//     <div>
//       <p>Theme: {theme}</p>
//       <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
//         Toggle Theme
//       </button>
//       <p>Username: {username}</p>
//       <input
//         type="text"
//         value={username}
//         onChange={(e) => setUsername(e.target.value)}
//         placeholder="Enter username"
//       />
//     </div>
//   );
// }
How it works: The `useLocalStorage` custom hook provides a convenient way to synchronize a React component's state with the browser's `localStorage`. When the component mounts, it attempts to load the stored value; otherwise, it uses an `initialValue`. Any subsequent changes to the state automatically update `localStorage` via a `useEffect` hook. This ensures that data persists across browser sessions, enhancing user experience without requiring a backend.

Need help integrating this into your project?

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

Hire DigitalCodeLabs