diff options
Diffstat (limited to 'packages/tweetdeck/src/hooks/usePersistentState.ts')
| -rw-r--r-- | packages/tweetdeck/src/hooks/usePersistentState.ts | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/packages/tweetdeck/src/hooks/usePersistentState.ts b/packages/tweetdeck/src/hooks/usePersistentState.ts new file mode 100644 index 0000000..7465f53 --- /dev/null +++ b/packages/tweetdeck/src/hooks/usePersistentState.ts @@ -0,0 +1,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; +} |
