Skip to content

Instantly share code, notes, and snippets.

@cmrigney
Created September 5, 2023 19:10
Show Gist options
  • Select an option

  • Save cmrigney/399f755acd06591514139a333d4f972a to your computer and use it in GitHub Desktop.

Select an option

Save cmrigney/399f755acd06591514139a333d4f972a to your computer and use it in GitHub Desktop.
useLocalStorage implemented with useSyncExternalStore
export function useLocalStorage<T>(key: string, initialValue: T) {
const store = useMemo(
() => getLocalStorageStore(key, initialValue),
[key, initialValue],
);
const currentValue = useSyncExternalStore(store.subscribe, store.getSnapshot);
const setValue = useCallback(
(value: T | ((value: T) => T)): void => {
const newStoredValue =
value instanceof Function ? value(currentValue) : value;
store.update(newStoredValue);
},
[currentValue, store],
);
return [currentValue, setValue] as const;
}
function getLocalStorageStore<T>(key: string, initialValue: T) {
const subscribe = (callback: () => void) => {
// Prevent build error "window is undefined" but keeps working
if (typeof window === 'undefined') {
// eslint-disable-next-line @typescript-eslint/no-empty-function
return () => {};
}
window.addEventListener(`local-storage-${key}` as any, callback);
return () => {
window.removeEventListener(`local-storage-${key}` as any, callback);
};
};
const getSnapshot = (): T => {
// Prevent build error "window is undefined" but keeps working
if (typeof window === 'undefined') {
return initialValue;
}
try {
const item = localStorage.getItem(key);
e2eLogger(`got value to localStorage ${key}: ${JSON.stringify(item)}`);
return item ? JSON.parse(item) : initialValue;
} catch (error: unknown) {
console.error('getting stored value for key:', key, error);
return initialValue;
}
};
const update = (value: T): void => {
// Prevent build error "window is undefined" but keeps working
if (typeof window === 'undefined') {
console.warn(
`Tried setting localStorage key “${key}” even though environment is not a client`,
);
}
try {
localStorage.setItem(key, JSON.stringify(value));
// We dispatch a custom event so every useLocalStorage hook are notified
window.dispatchEvent(new Event(`local-storage-${key}`));
e2eLogger(
`saved value to localStorage ${key}: ${JSON.stringify(
value,
)}`,
);
} catch (error: unknown) {
console.error('setting stored value for key:', key, error);
}
};
return {
subscribe,
getSnapshot,
update,
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment