useLocalStorage

React side-effect hook that manages a single localStorage key

useLocalStorage binds a React state to a localStorage key. It returns a [value, setValue] tuple similar to useState. The value is read from storage on mount and written back whenever you call setValue. Setting the value to null removes the key. Custom serializers can be provided for non-string data types, and the hook listens for cross-tab storage events by default so that changes in one tab are reflected in others.

When to Use

  • Persisting user preferences (theme, language, layout) across page reloads
  • Caching form drafts or application state so users can resume where they left off
  • Sharing simple state between browser tabs via the storage event

Notes

  • Persistence: Data survives page reloads and browser restarts. Use useSessionStorage if you only need data for the current session.
  • Cross-tab sync: By default, the hook listens for storage events so changes in one tab update other tabs. Disable this with listenToStorageChanges: false.
  • Custom serialization: For objects or non-string values, provide serializer.read and serializer.write functions in the options. The default behavior uses JSON serialization for objects and raw strings for string values.
  • See also useSessionStorage for session-scoped storage and useCookie for cookie-based persistence.

Usage

Live Editor
function Demo() {
  // bind string
  const [value, setValue] = useLocalStorage("my-key", "key");
  
  // bind object with custom serializer
  const [myObj, setMyObj] = useLocalStorage(
    "myObj",
    {
      name: "test",
    },
    {
      serializer: {
        read: (val) => {
          console.log("read", val);
          return JSON.parse(val);
        },
        write: (val) => {
          console.log("write", val);
          return JSON.stringify(val);
        },
      },
    }
  );

  return (
    <div>
      <div>
        <h3>String Value</h3>
        <div>Value: {value}</div>
        <button onClick={() => setValue("bar")}>Set to "bar"</button>
        <button onClick={() => setValue("baz")}>Set to "baz"</button>
        <button onClick={() => setValue(null)}>Remove</button>
      </div>
      
      <div style={{ marginTop: "20px" }}>
        <h3>Object Value</h3>
        <div>Object: {JSON.stringify(myObj)}</div>
        <button onClick={() => setMyObj({ name: "updated" })}>
          Update Object
        </button>
        <button onClick={() => setMyObj({ name: "test", count: 1 })}>
          Add Property
        </button>
        <button onClick={() => setMyObj(null)}>Remove Object</button>
      </div>
    </div>
  );
};
Result

API

useLocalStorage

Returns

readonly [T | null, React.Dispatch<React.SetStateAction<T | null>>]: A tuple with the following elements:

  • The current value of the localStorage.
  • A function to update the value of the localStorage.

Arguments

ArgumentDescriptionTypeDefaultValue
keykeystring (Required)-
defaultValuedefault valueT | undefined-
optionsoptional paramsUseLocalStorageOptions<T> | undefined-

UseLocalStorageOptions

PropertyDescriptionTypeDefaultValue
serializerCustom data serializationUseLocalStorageSerializer<T>-
onErrorOn error callback(error: unknown) => voidconsole.error
effectStorageValueset to storage when nodata in first mount, deprecatedT | (() => T)-
mountStorageValueset to storage when nodata in first mountT | (() => T)-
listenToStorageChangeslisten to storage changesbooleantrue

UseLocalStorageSerializer

PropertyDescriptionTypeDefaultValue
readCustom data read(raw: string) => T (Required)-
writeCustom data write(value: T) => string (Required)-