import * as React from "react"; function dispatchStorageEvent(key, newValue) { window.dispatchEvent(new StorageEvent("storage", { key, newValue })); } const setLocalStorageItem = (key, value) => { if (typeof window === "undefined") { return; } const stringifiedValue = JSON.stringify(value); window.localStorage.setItem(key, stringifiedValue); dispatchStorageEvent(key, stringifiedValue); }; const removeLocalStorageItem = (key) => { if (typeof window === "undefined") { return; } window.localStorage.removeItem(key); dispatchStorageEvent(key, null); }; const getLocalStorageItem = (key) => { if (typeof window === "undefined") { return null; } const json = window.localStorage.getItem(key); if (json === null) { return null; } try { return JSON.parse(json); } catch (e) { console.warn(e); return json ?? null; } }; // Cache the localStorage state to prevent infinite loops let cachedLocalStorage = {}; let cachedKeys: string[] | null = null; const useLocalStorageGetSnapshot = () => { if (typeof window === "undefined") { return {}; } // Create a stable snapshot by caching the keys and values const currentKeys = Object.keys(window.localStorage); // Check if keys have changed const keysChanged = !cachedKeys || cachedKeys.length !== currentKeys.length || !currentKeys.every((key, index) => key === cachedKeys![index]); if (keysChanged) { // Update cache if keys have changed cachedKeys = currentKeys; cachedLocalStorage = currentKeys.reduce((acc, key) => { acc[key] = window.localStorage.getItem(key); return acc; }, {}); } else { // Check if any values have changed let valuesChanged = false; for (const key of currentKeys) { const currentValue = window.localStorage.getItem(key); if (cachedLocalStorage[key] !== currentValue) { valuesChanged = true; cachedLocalStorage[key] = currentValue; } } } return cachedLocalStorage; }; const useLocalStorageSubscribe = (callback) => { window.addEventListener("storage", callback); return () => window.removeEventListener("storage", callback); }; const getLocalStorageServerSnapshot = () => { return {}; }; export function useLocalStorage() { React.useSyncExternalStore( useLocalStorageSubscribe, useLocalStorageGetSnapshot, getLocalStorageServerSnapshot, ); const hasItem = React.useCallback((key: string) => { return getLocalStorageItem(key) !== null; }, []); const setItem = React.useCallback((key: string, value: string) => { try { if (value === null || value === undefined) { removeLocalStorageItem(key); } else { setLocalStorageItem(key, value); } } catch (e) { console.warn(e); } }, []); return React.useMemo( () => ({ getItem: getLocalStorageItem, hasItem, setItem }), [hasItem, setItem], ); }