JAVASCRIPT
Persist State to Local Storage with useLocalStorage Hook
Build a `useLocalStorage` React hook to easily persist component state in the browser's local storage. Handles initial values, JSON serialization, and updates.
import React, { useState, useEffect } from 'react';
// Custom hook for persisting state to localStorage
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 reading from localStorage:", error);
return initialValue;
}
});
// useEffect to update local storage when the state changes
useEffect(() => {
try {
window.localStorage.setItem(key, JSON.stringify(storedValue));
} catch (error) {
console.error("Error writing to localStorage:", error);
}
}, [key, storedValue]); // Re-run if key or storedValue changes
return [storedValue, setStoredValue];
}
// Example component using the custom hook
function UserSettings() {
const [theme, setTheme] = useLocalStorage('appTheme', 'light');
const [userName, setUserName] = useLocalStorage('userName', '');
const toggleTheme = () => {
setTheme(prevTheme => (prevTheme === 'light' ? 'dark' : 'light'));
};
return (
<div style={{ padding: '20px', background: theme === 'dark' ? '#333' : '#f0f0f0', color: theme === 'dark' ? '#fff' : '#333' }}>
<h1>User Settings</h1>
<p>Current Theme: {theme}</p>
<button onClick={toggleTheme}>Toggle Theme</button>
<hr />
<label>
Your Name:
<input
type="text"
value={userName}
onChange={(e) => setUserName(e.target.value)}
style={{ marginLeft: '10px', padding: '5px' }}
/>
</label>
<p>Hello, {userName || 'Guest'}!</p>
<p><em>Refresh the page to see state persistence.</em></p>
</div>
);
}
export default UserSettings;
How it works: This custom hook, `useLocalStorage`, provides a convenient way to manage component state that needs to persist across browser sessions. It leverages `useState` for the component's reactive state and `useEffect` to synchronize this state with `localStorage`. On initialization, it attempts to load the value from `localStorage`; if not found or an error occurs, it uses the provided `initialValue`. Any subsequent changes to the state automatically update `localStorage`, ensuring data is saved.