Skip to Content
HooksuseLocalStorage

useLocalStorage

useLocalStorage persists React state in localStorage with safe JSON serialization, functional updates, and explicit reset and remove helpers.

Live Example

Persistent draft editor

This demo shows the common pattern: state stays in sync with localStorage, so reloading the page keeps the draft.

Persistent draft

localStorage-backed state

Saved locally

Refresh the page and this text stays in place. The hook updates React state and `localStorage` together, with reset and remove helpers for the stored key.

Storage support: Unavailable.

Import

import { useLocalStorage } from "react-rsc-kit/client";

Signature

const { value, setValue, remove, reset, isSupported } = useLocalStorage<T>(key, initialValue);

Parameters

NameTypeDescription
keystringlocalStorage key used to read, write, remove, and reset the stored value.
initialValueT | () => TFallback value used when storage is empty, invalid, or unavailable. Supports lazy initialization.

Returns

KeyTypeDescription
valueTCurrent React state value.
setValueDispatch<SetStateAction<T>>Updates state and writes the next value to localStorage. Supports functional updates.
remove() => voidRemoves the storage key and resets state back to the fallback value.
reset() => voidRestores the fallback value and writes it back to localStorage.
isSupportedbooleanWhether localStorage is available in the current environment.

Usage

"use client"; import { useLocalStorage } from "react-rsc-kit/client"; export function DraftMessage() { const { value: draft, setValue, remove } = useLocalStorage("draft-message", ""); return ( <div> <textarea value={draft} onChange={(event) => setValue(event.target.value)} /> <button type="button" onClick={remove}> Clear draft </button> </div> ); }
"use client"; import { useLocalStorage } from "react-rsc-kit/client"; interface UserPreferences { compactMode: boolean; itemsPerPage: number; tags: string[]; } export function PreferencesPanel() { const { value: preferences, setValue, reset, } = useLocalStorage<UserPreferences>("user-preferences", { compactMode: false, itemsPerPage: 20, tags: ["react", "typescript"], }); return ( <div> <p>{preferences.itemsPerPage} items</p> <button type="button" onClick={() => setValue((currentValue) => ({ ...currentValue, compactMode: !currentValue.compactMode, })) } > Toggle compact mode </button> <button type="button" onClick={reset}> Reset preferences </button> </div> ); }

Notes

  • The hook reads existing stored JSON first and falls back to initialValue when the key is missing, malformed, or unavailable.
  • remove() and reset() always resolve the fallback from the latest initialValue you pass for the same key (handy when defaults come from props). Changing initialValue does not overwrite an existing stored value until you call setValue, reset, or remove.
  • setValue avoids writing to storage when the resolved value is unchanged (Object.is), which reduces work for no-op functional updates.
  • remove() clears the key from localStorage, while reset() writes the fallback value back into storage.
  • Explicit undefined values are preserved by the hook’s serializer, but values still need to be JSON-serializable to persist correctly.
  • In non-browser environments, the hook falls back to React state and reports isSupported as false.
Last updated on