Skip to content

Instantly share code, notes, and snippets.

@tluyben
Created October 21, 2024 09:41
Show Gist options
  • Save tluyben/fe80c33b60bff9a4af746f9888c861f8 to your computer and use it in GitHub Desktop.
Save tluyben/fe80c33b60bff9a4af746f9888c861f8 to your computer and use it in GitHub Desktop.
import { useState, useEffect } from 'react';
const subscribers = new Map<string, Set<React.Dispatch<any>>>();
function useLocalStorage<T>(key: string, initialValue: T) {
// State to store our value
const [storedValue, setStoredValue] = useState<T>(() => {
try {
const item = window.localStorage.getItem(key);
return item ? (JSON.parse(item) as T) : initialValue;
} catch (error) {
console.error(error);
return initialValue;
}
});
// Manage subscriptions
useEffect(() => {
let subs = subscribers.get(key);
if (!subs) {
subs = new Set();
subscribers.set(key, subs);
}
subs.add(setStoredValue);
return () => {
subs!.delete(setStoredValue);
if (subs!.size === 0) {
subscribers.delete(key);
}
};
}, [key]);
// Update localStorage when storedValue changes
useEffect(() => {
try {
window.localStorage.setItem(key, JSON.stringify(storedValue));
} catch (error) {
console.error(error);
}
}, [key, storedValue]);
// Cross-tab synchronization
useEffect(() => {
const handleStorageChange = (event: StorageEvent) => {
if (event.key === key) {
try {
const newValue = event.newValue ? (JSON.parse(event.newValue) as T) : initialValue;
setStoredValue(newValue);
// Notify subscribers
const subs = subscribers.get(key);
if (subs) {
subs.forEach((sub) => {
if (sub !== setStoredValue) {
sub(newValue);
}
});
}
} catch (error) {
console.error(error);
}
}
};
window.addEventListener('storage', handleStorageChange);
return () => {
window.removeEventListener('storage', handleStorageChange);
};
}, [key, initialValue]);
// Function to set the value and notify subscribers
const setValue = (value: T | ((val: T) => T)) => {
try {
const valueToStore = value instanceof Function ? value(storedValue) : value;
setStoredValue(valueToStore);
window.localStorage.setItem(key, JSON.stringify(valueToStore));
// Notify other subscribers
const subs = subscribers.get(key);
if (subs) {
subs.forEach((sub) => {
if (sub !== setStoredValue) {
sub(valueToStore);
}
});
}
} catch (error) {
console.error(error);
}
};
return [storedValue, setValue] as [T, typeof setValue];
}
export default useLocalStorage;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment