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
storageevent
Notes
- Persistence: Data survives page reloads and browser restarts. Use
useSessionStorageif you only need data for the current session. - Cross-tab sync: By default, the hook listens for
storageevents so changes in one tab update other tabs. Disable this withlistenToStorageChanges: false. - Custom serialization: For objects or non-string values, provide
serializer.readandserializer.writefunctions in the options. The default behavior uses JSON serialization for objects and raw strings for string values. - See also
useSessionStoragefor session-scoped storage anduseCookiefor 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
| Argument | Description | Type | DefaultValue |
|---|---|---|---|
| key | key | string (Required) | - |
| defaultValue | default value | T | undefined | - |
| options | optional params | UseLocalStorageOptions<T> | undefined | - |
UseLocalStorageOptions
| Property | Description | Type | DefaultValue |
|---|---|---|---|
| serializer | Custom data serialization | UseLocalStorageSerializer<T> | - |
| onError | On error callback | (error: unknown) => void | console.error |
| effectStorageValue | set to storage when nodata in first mount, deprecated | T | (() => T) | - |
| mountStorageValue | set to storage when nodata in first mount | T | (() => T) | - |
| listenToStorageChanges | listen to storage changes | boolean | true |
UseLocalStorageSerializer
| Property | Description | Type | DefaultValue |
|---|---|---|---|
| read | Custom data read | (raw: string) => T (Required) | - |
| write | Custom data write | (value: T) => string (Required) | - |