MCPcopy Create free account
hub / github.com/AmazingAng/PolyWorld / useLocalStorage

Function useLocalStorage

src/hooks/useLocalStorage.ts:13–59  ·  view source on GitHub ↗
(
  key: string,
  defaultValue: T
)

Source from the content-addressed store, hash-verified

11 * - Graceful fallback for storage full / private mode
12 */
13export function useLocalStorage<T extends { version: number }>(
14 key: string,
15 defaultValue: T
16): [T, (value: T | ((prev: T) => T)) => void, boolean] {
17 // Always start with default for SSR consistency
18 const [state, setState] = useState<T>(defaultValue);
19 const [isHydrated, setIsHydrated] = useState(false);
20
21 // Hydrate from localStorage after mount
22 useEffect(() => {
23 try {
24 const raw = localStorage.getItem(key);
25 if (raw) {
26 const parsed = JSON.parse(raw) as T;
27 if (parsed.version === defaultValue.version) {
28 setState(parsed);
29 }
30 }
31 } catch {
32 // corrupted or unavailable
33 }
34 setIsHydrated(true);
35 // eslint-disable-next-line react-hooks/exhaustive-deps
36 }, [key]);
37
38 // Persist changes — only after hydration is complete
39 useEffect(() => {
40 if (!isHydrated) return;
41 try {
42 localStorage.setItem(key, JSON.stringify(state));
43 } catch {
44 // storage full or unavailable — silently fail
45 }
46 }, [key, state, isHydrated]);
47
48 const setValue = useCallback(
49 (value: T | ((prev: T) => T)) => {
50 setState((prev) => {
51 const next = typeof value === "function" ? (value as (prev: T) => T)(prev) : value;
52 return next;
53 });
54 },
55 []
56 );
57
58 return [state, setValue, isHydrated];
59}

Callers 3

useWatchlistFunction · 0.90
usePreferencesFunction · 0.90
useAlertsFunction · 0.90

Calls

no outgoing calls

Tested by

no test coverage detected