Sync react state to local storage.

A typesafe React hook that seamlessly syncs your state with LocalStorage. Smart parsing for BigInt, Booleans, Numbers, and JSON Objects.

use-local-state.ts
import { type Dispatch, type SetStateAction, useEffect, useState } from "react";

export function useLocalState<T>(
  initialState: T,
  key: string,
): [T, Dispatch<SetStateAction<T>>, () => void] {
  const [value, setValue] = useState(() => {
    const stringLocalValue = localStorage.getItem(key);

    if (!stringLocalValue) {
      return initialState;
    }

    if (typeof initialState === "bigint") {
      return BigInt(stringLocalValue) as T;
    }

    if (typeof initialState === "boolean") {
      return Boolean(stringLocalValue === "true") as T;
    }

    if (typeof initialState === "number") {
      return Number(stringLocalValue) as T;
    }

    if (typeof initialState === "object") {
      return JSON.parse(stringLocalValue) as T;
    }

    return String(stringLocalValue) as T;
  });

  const setLocalStorage = (value: T) => {
    if (typeof initialState === "object") {
      localStorage.setItem(key, JSON.stringify(value));
    } else {
      localStorage.setItem(key, String(value));
    }
  };

  // biome-ignore lint/correctness/useExhaustiveDependencies: <>
  useEffect(() => {
    setLocalStorage(value);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [value]);

  const reset = () => {
    setValue(initialState);
    setLocalStorage(initialState);
  };

  return [value, setValue, reset];
}
Try refreshing the page to see the magic.

Primitive Sync

Restore values as Numbers, not Strings.

Boolean Guards

Persist toggles and switches effortlessly.

Notifications

JSON Objects

Automatic parsing for complex data structures.

Live JSON Output

{
  "username": "",
  "plan": "",
  "emailUpdates": ""
}
1

Typesafe Parsing

Leverages your initial state type to ensure your data is cast correctly when retrieved.

2

Cross-Tab Sync

Uses the Storage Event to synchronize state across multiple open tabs automatically.

3

Client-Only

Designed strictly for the browser. Use a mount guard for SSR hydration.

Did you like this project?

Please give it a star on GitHub. Thank you!

You might also be interested in use-sortable-list.