# useReadLocalStorage > Read a localStorage key without writing it, reactively. - Category: State - Package: `hookli` (install with `npm i hookli`) - Docs: https://hookli.vercel.app/docs/use-read-local-storage ## Signature ```ts useReadLocalStorage(key: string, options?: UseReadLocalStorageOptions): T | null ``` ## Parameters - `key`: `string` — The localStorage key to observe. - `options`: `UseReadLocalStorageOptions` (default: `{}`) — Optional custom deserializer and hydration flag. ## Returns - `value`: `T | null` — The parsed value, or null when the key is absent. Re-renders when the key changes in another tab (storage event) or via a local-storage event dispatched in this tab. ## Types ### UseReadLocalStorageOptions Custom deserialization and hydration behaviour. - `deserializer`: `(value: string) => T` — Parse the stored string into a value. Defaults to JSON.parse, falling back to the raw string. - `initializeWithValue`: `boolean` (default: `true`) — Read localStorage synchronously on mount. Set false to defer to after hydration and avoid SSR mismatches. ## Usage ```tsx import { useReadLocalStorage } from "hookli"; export function Demo() { const theme = useReadLocalStorage("theme"); return

Saved theme: {theme ?? "none"}

; } ``` ## Source `src/hooks/use-read-local-storage/use-read-local-storage.ts` ```ts import { useCallback, useEffect, useState } from "react"; import { useEventListener } from "../use-event-listener/use-event-listener"; interface UseReadLocalStorageOptions { deserializer?: (value: string) => T; initializeWithValue?: boolean; } const IS_SERVER = typeof window === "undefined"; export function useReadLocalStorage( key: string, options: UseReadLocalStorageOptions = {}, ): T | null { const { initializeWithValue = true } = options; const deserializer = useCallback( (value: string): T | undefined => { if (options.deserializer) return options.deserializer(value); if (value === "undefined") return undefined; try { return JSON.parse(value); } catch { return value as unknown as T; } }, [options], ); const readValue = useCallback((): T | null => { if (IS_SERVER) return null; try { const raw = window.localStorage.getItem(key); return raw ? (deserializer(raw) as T) : null; } catch { return null; } }, [key, deserializer]); const [storedValue, setStoredValue] = useState(() => initializeWithValue ? readValue() : null, ); useEffect(() => { setStoredValue(readValue()); }, [key]); const handleStorageChange = useCallback( (event: StorageEvent) => { if (event.key && event.key !== key) return; setStoredValue(readValue()); }, [key, readValue], ); useEventListener("storage", handleStorageChange); useEventListener("local-storage", handleStorageChange); return storedValue; } ```