1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
import { useEffect, useRef, useState } from "react";
type Initializer<T> = T | (() => T);
const isBrowser = typeof window !== "undefined";
function readFromStorage<T>(key: string, fallback: Initializer<T>): T {
if (!isBrowser) {
return typeof fallback === "function" ? (fallback as () => T)() : fallback;
}
try {
const raw = window.localStorage.getItem(key);
if (raw) {
return JSON.parse(raw) as T;
}
} catch (error) {
console.warn("Failed to parse localStorage value", { key, error });
}
return typeof fallback === "function" ? (fallback as () => T)() : fallback;
}
export function usePersistentState<T>(key: string, initial: Initializer<T>) {
const initialRef = useRef<T | null>(null);
if (initialRef.current === null) {
initialRef.current = readFromStorage<T>(key, initial);
}
const [value, setValue] = useState<T>(() => initialRef.current as T);
useEffect(() => {
if (!isBrowser) return;
try {
window.localStorage.setItem(key, JSON.stringify(value));
} catch (error) {
console.warn("Failed to write localStorage value", { key, error });
}
}, [key, value]);
return [value, setValue] as const;
}
|