A custom React Hook that synchronizes component state with localStorage, following the DRY principle. This hook encapsulates localStorage logic, making it reusable across multiple components for cleaner and more maintainable code.
⚛️ Hook Declaration
import React, { useState, useEffect, useRef } from "react";
function useLocalStorageState(
key,
defaultValue = '',
{ serialize = JSON.stringify, deserialize = JSON.parse } = {},
) {
// Initialize state with local storage value (if available) or default value
const [state, setState] = useState(() => {
const valueInLocalStorage = window.localStorage.getItem(key);
if (valueInLocalStorage) {
return deserialize(valueInLocalStorage);
}
// If default value is a function, execute it, else return default value
return typeof defaultValue === 'function' ? defaultValue() : defaultValue;
});
// Ref to keep track of previous key
const prevKeyRef = useRef(key);
// Effect to update local storage when state or key changes
useEffect(() => {
// Retrieve previous key
const prevKey = prevKeyRef.current;
// If key has changed, remove previous key from local storage
if (prevKey !== key) {
window.localStorage.removeItem(prevKey);
}
// Update ref with current key
prevKeyRef.current = key;
// Set current state to local storage
window.localStorage.setItem(key, serialize(state));
}, [key, state, serialize]);
// Return state and setState function
return [state, setState];
}
export { useLocalStorageState };
🛠️ Hook Implementation
function YourComponentNameWhereYouNeed(props) {
// Example usage from a real project
const [localLogs, setLocalLogs] = useLocalStorageState('localLogs')
return (
<div>
{/* Your component content */}
</div>
)
}
🔑 Key Features
- Automatic Synchronization: State changes are automatically saved to localStorage
- Serialization Support: Configurable serialization/deserialization methods
- Dynamic Keys: Handles localStorage key changes gracefully
- Default Values: Supports both static values and factory functions
- SSR Safe: Properly handles server-side rendering scenarios
💡 Use Cases
Perfect for persisting:
- User preferences and settings
- Form data and drafts
- Shopping cart contents
- Theme preferences
- Authentication tokens
- Any state that should survive page refreshes
📝 Advanced Usage
// With custom serialization
const [complexData, setComplexData] = useLocalStorageState('complexData', {}, {
serialize: (value) => JSON.stringify(value),
deserialize: (value) => JSON.parse(value)
});
// With factory function as default
const [timestamp, setTimestamp] = useLocalStorageState('timestamp', () => Date.now());