useLocalStorage
Persist state in localStorage to keep data between page reloads in React apps.
useLocalStorage
A custom React hook to synchronize a stateful value with localStorage
. It enables persistent state by saving the value to browser storage and retrieving it on page load. Ideal for user preferences, theme settings, or any data you want to keep between sessions.
📦 Installation
Works out of the box with React and Next.js projects. No external dependencies required.
🧠 Purpose
\useLocalStorage\ simplifies persistent state management by abstracting localStorage read/write operations and syncing with React state.
💡 Use Cases
- Persist user preferences (dark mode, language)
- Keep form data on page reloads
- Cache temporary data between sessions
- Store tokens or auth flags (with caution)
📁 Hook Code
import { useState, useEffect } from "react";
export function useLocalStorage<T>(key: string, initialValue: T) {
const [storedValue, setStoredValue] = useState<T>(() => {
if (typeof window === "undefined") return initialValue;
try {
const item = window.localStorage.getItem(key);
return item ? (JSON.parse(item) as T) : initialValue;
} catch (error) {
console.warn("useLocalStorage: error reading key", key, error);
return initialValue;
}
});
const setValue = (value: T | ((val: T) => T)) => {
try {
const valueToStore =
value instanceof Function ? value(storedValue) : value;
setStoredValue(valueToStore);
if (typeof window !== "undefined") {
window.localStorage.setItem(key, JSON.stringify(valueToStore));
}
} catch (error) {
console.warn("useLocalStorage: error setting key", key, error);
}
};
return [storedValue, setValue] as const;
}
import { useState, useEffect } from "react";
export function useLocalStorage(key, initialValue) {
const [storedValue, setStoredValue] = useState(() => {
if (typeof window === "undefined") return initialValue;
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
console.warn("useLocalStorage: error reading key", key, error);
return initialValue;
}
});
const setValue = (value) => {
try {
const valueToStore =
value instanceof Function ? value(storedValue) : value;
setStoredValue(valueToStore);
if (typeof window !== "undefined") {
window.localStorage.setItem(key, JSON.stringify(valueToStore));
}
} catch (error) {
console.warn("useLocalStorage: error setting key", key, error);
}
};
return [storedValue, setValue];
}
🧪 Example
import React from "react";
import { useLocalStorage } from "@/hooks/useLocalStorage";
export default function DarkModeToggle() {
const [darkMode, setDarkMode] = useLocalStorage<boolean>("darkMode", false);
return (
<button onClick={() => setDarkMode((prev) => !prev)}>
{darkMode ? "Switch to Light Mode" : "Switch to Dark Mode"}
</button>
);
}
import React from "react";
import { useLocalStorage } from "@/hooks/useLocalStorage";
function DarkModeToggle() {
const [darkMode, setDarkMode] = useLocalStorage("darkMode", false);
return (
<button onClick={() => setDarkMode(prev => !prev)}>
{darkMode ? "Switch to Light Mode" : "Switch to Dark Mode"}
</button>
);
}
export default DarkModeToggle;
🧩 Hook Signature
function useLocalStorage<T>(
key: string,
initialValue: T
): readonly [T, (value: T | ((val: T) => T)) => void];
📝 Parameters
Prop | Type | Default |
---|---|---|
initialValue | T | - |
key | string | - |
🎯 Returns
Prop | Type | Default |
---|---|---|
setValue | (value: T | (val: T) => T) => void | - |
storedValue | T | - |
🧯 How It Works
LocalStorage Sync
On initialization, it tries to read the value from localStorage. On updates, it writes the new value back to localStorage, keeping React state and browser storage in sync.
🏁 Summary
- ✅ Persistent state synced with localStorage
- ✅ Supports functional updates
- ✅ Works with any serializable value
- ✅ TypeScript friendly with generics
🙋 Contribution
Found a bug or improvement? Submit a PR on GitHub