Build a Custom use Local Storage Hook in React: Simplify Persistent State

By Priya
May 10, 2025

Follow us on


Learn how to build and use a custom React hook called use Local Storage to manage persistent data easily. Follow this beginner-friendly tutorial with code examples and practical explanations.

Build a Custom use Local Storage Hook in React: Simplify Persistent State

When building web applications, it’s common to store data that should persist even after the user refreshes the page or closes the browser. That’s where localStorage becomes useful.

However, using localStorage manually inside React components can get messy—especially when managing multiple keys. So, let’s simplify our code by building a custom hook called useLocalStorage.

This hook will:

  • Get the value from localStorage on load

  • Store new values when the state updates

  • Sync state between component and localStorage seamlessly


🚀 Why Use a Custom Hook for localStorage?

Benefits include:

  • Cleaner code

  • Reusability across components

  • Built-in state management with useState

  • Persistence with localStorage


📁 Folder Setup

If you already have a React app, skip to the next step. Otherwise, create one using:

bash
npx create-react-app localstorage-hook-app
cd localstorage-hook-app
npm start

🛠️ Step 1: Create the useLocalStorage Hook

Create a new file named useLocalStorage.js inside your src/ directory:

// src/useLocalStorage.js

import { useState, useEffect } from 'react';

function useLocalStorage(key, initialValue) {
  const [value, setValue] = useState(() => {
    try {
      const localValue = window.localStorage.getItem(key);
      return localValue ? JSON.parse(localValue) : initialValue;
    } catch (err) {
      console.error('Error reading localStorage:', err);
      return initialValue;
    }
  });

  useEffect(() => {
    try {
      window.localStorage.setItem(key, JSON.stringify(value));
    } catch (err) {
      console.error('Error writing to localStorage:', err);
    }
  }, [key, value]);

  return [value, setValue];
}

export default useLocalStorage;

Explanation

Line Code Concept 
                                      useState() Initializes state from localStorage or initialValue
                                      useEffect() Watches for changes in state and saves them to localStorage
              JSON.parse() / JSON.stringify()
Handles objects and arrays correctly
 
 

Why use a function in useState()?
It ensures the code runs only once when the component mounts (lazy initialization).


🧪 Step 2: Use It in a Component

Let’s build a simple app that stores the user's name.

Create a new component App.js or replace its content with:

import React from 'react';
import useLocalStorage from './useLocalStorage';
import './App.css';

function App() {
  const [name, setName] = useLocalStorage('username', '');

  return (
    <div className="App">
      <h1>Hello {name || 'Guest'}!</h1>
      <input
        type="text"
        value={name}
        onChange={(e) => setName(e.target.value)}
        placeholder="Enter your name"
      />
    </div>
  );
}

export default App;

🔍 What’s Happening Here?

  • The useLocalStorage hook is used just like useState

  • The value is persisted in the browser's storage

  • On refresh or revisit, the name stays the same

🎨 Optional Styling (App.css)

 
.App {
  font-family: sans-serif;
  text-align: center;
  margin-top: 100px;
}

input {
  padding: 10px;
  font-size: 1rem;
  margin-top: 10px;
}

🧼 Step 3: Benefits of This Hook

Feature Benefit
✅ Reusable Use for theme, tokens, preferences
✅ Persistent Remembers user input
✅ Compact Less repetitive code
✅ JSON Support Handles arrays/objects easily

💎 Bonus Features You Can Add

Here are some great ideas to enhance the hook:

1. Remove Item Function

Let users clear the stored value:

window.localStorage.removeItem('username');

You can even return this as part of the hook:

return [value, setValue, () => localStorage.removeItem(key)];

2. Sync Between Tabs

Use the storage event:

useEffect(() => {
  const sync = (e) => {
    if (e.key === key) {
      setValue(JSON.parse(e.newValue));
    }
  };
  window.addEventListener('storage', sync);
  return () => window.removeEventListener('storage', sync);
}, []);

3. Custom Serialization

For advanced cases, pass your own parse and stringify methods:

function useLocalStorage(key, initialValue, parseFn = JSON.parse, stringifyFn = JSON.stringify) {
  // Use parseFn and stringifyFn
}

🧑‍🎓 Learning Outcomes

By now, you’ve learned:

Concept Application
React custom hooks Reusable logic in function components
localStorage API Persistent data storage in browser
JSON parsing Handling structured data safely
useEffect React side effects (writing to storage)
Hook parameters Making hooks flexible (e.g., keys, default values)

🔄 Full Code Recap

useLocalStorage.js

import { useState, useEffect } from 'react';

function useLocalStorage(key, initialValue) {
  const [value, setValue] = useState(() => {
    try {
      const item = window.localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      console.log(error);
      return initialValue;
    }
  });

  useEffect(() => {
    try {
      window.localStorage.setItem(key, JSON.stringify(value));
    } catch (error) {
      console.log(error);
    }
  }, [key, value]);

  return [value, setValue];
}

export default useLocalStorage;

App.js

import React from 'react';
import useLocalStorage from './useLocalStorage';
import './App.css';

function App() {
  const [name, setName] = useLocalStorage('username', '');

  return (
    <div className="App">
      <h1>Hello {name || 'Guest'}!</h1>
      <input
        type="text"
        value={name}
        onChange={(e) => setName(e.target.value)}
        placeholder="Enter your name"
      />
    </div>
  );
}

export default App;

🚀 Conclusion

Creating a custom useLocalStorage hook in React is a powerful way to make your applications smarter, faster, and user-friendly. With just a few lines of reusable code, you unlock the ability to persist user preferences, form inputs, UI themes, and more—even after page refresh.

✅ Clean.
✅ Flexible.
✅ Perfect for real-world apps.

Use this hook in every project where you want to remember user data. It’ll save you time—and your users will love the experience.


© 2025 Revolve Base. All rights reserved.