{"id":13475791,"url":"https://github.com/astoilkov/use-local-storage-state","last_synced_at":"2025-05-14T15:06:50.454Z","repository":{"id":38420395,"uuid":"246913915","full_name":"astoilkov/use-local-storage-state","owner":"astoilkov","description":"React hook that persists data in localStorage","archived":false,"fork":false,"pushed_at":"2024-11-13T11:18:42.000Z","size":375,"stargazers_count":1190,"open_issues_count":5,"forks_count":39,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-04-09T19:13:29.231Z","etag":null,"topics":["hook","localstorage","persistent","react","usestate"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/astoilkov.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"license","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"astoilkov"}},"created_at":"2020-03-12T19:22:03.000Z","updated_at":"2025-04-09T12:58:48.000Z","dependencies_parsed_at":"2024-01-07T00:05:59.123Z","dependency_job_id":"a4075083-deb4-4ff9-aba2-493ce014ddb1","html_url":"https://github.com/astoilkov/use-local-storage-state","commit_stats":{"total_commits":505,"total_committers":13,"mean_commits":38.84615384615385,"dds":"0.49306930693069306","last_synced_commit":"52ad3e0d64dab80dcb8cfe8f140090077313b3b8"},"previous_names":[],"tags_count":90,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/astoilkov%2Fuse-local-storage-state","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/astoilkov%2Fuse-local-storage-state/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/astoilkov%2Fuse-local-storage-state/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/astoilkov%2Fuse-local-storage-state/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/astoilkov","download_url":"https://codeload.github.com/astoilkov/use-local-storage-state/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248094987,"owners_count":21046770,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hook","localstorage","persistent","react","usestate"],"created_at":"2024-07-31T16:01:23.620Z","updated_at":"2025-04-09T19:13:36.698Z","avatar_url":"https://github.com/astoilkov.png","language":"TypeScript","funding_links":["https://github.com/sponsors/astoilkov"],"categories":["TypeScript","Uncategorized","⚛️ React"],"sub_categories":["Uncategorized","React-specific libs:"],"readme":"# `use-local-storage-state`\n\n\u003e React hook that persist data in `localStorage`\n\n[![Downloads](https://img.shields.io/npm/dm/use-local-storage-state)](https://npm.chart.dev/use-local-storage-state)\n[![Gzipped Size](https://img.shields.io/bundlephobia/minzip/use-local-storage-state)](https://bundlephobia.com/result?p=use-local-storage-state)\n[![Build Status](https://img.shields.io/github/actions/workflow/status/astoilkov/use-local-storage-state/main.yml?branch=main)](https://github.com/astoilkov/use-local-storage-state/actions/workflows/main.yml)\n\n## Install\n\nReact 18 and above:\n```bash\nnpm install use-local-storage-state\n```\n\n⚠️ React 17 and below. For docs, go to the [react-17 branch](https://github.com/astoilkov/use-local-storage-state/tree/react-17).\n```bash\nnpm install use-local-storage-state@17\n```\n\n## Why\n\n- Actively maintained for the past 4 years — see [contributors](https://github.com/astoilkov/use-local-storage-state/graphs/contributors) page.\n- Production ready.\n- 689 B (brotlied).\n- SSR support.\n- Works with React 18 concurrent rendering and React 19.\n- Handles the `Window` [`storage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/storage_event) event and updates changes across browser tabs, windows, and iframe's. Disable with `storageSync: false`.\n- In-memory fallback when `localStorage` throws an error and can't store the data. Provides a `isPersistent` API to let you notify the user their data isn't currently being stored.\n- Aiming for high-quality with [my open-source principles](https://astoilkov.com/my-open-source-principles).\n\n## Usage\n\n```typescript\nimport useLocalStorageState from 'use-local-storage-state'\n\nexport default function Todos() {\n    const [todos, setTodos] = useLocalStorageState('todos', {\n        defaultValue: ['buy avocado', 'do 50 push-ups']\n    })\n}\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eTodo list example\u003c/summary\u003e\n\u003cp\u003e\u003c/p\u003e\n\n```tsx\nimport React, { useState } from 'react'\nimport useLocalStorageState from 'use-local-storage-state'\n\nexport default function Todos() {\n    const [todos, setTodos] = useLocalStorageState('todos', {\n        defaultValue: ['buy avocado']\n    })\n    const [query, setQuery] = useState('')\n\n    function onClick() {\n        setQuery('')\n        setTodos([...todos, query])\n    }\n\n    return (\n        \u003c\u003e\n            \u003cinput value={query} onChange={e =\u003e setQuery(e.target.value)} /\u003e\n            \u003cbutton onClick={onClick}\u003eCreate\u003c/button\u003e\n            {todos.map(todo =\u003e (\n                \u003cdiv\u003e{todo}\u003c/div\u003e\n            ))}\n        \u003c/\u003e\n    )\n}\n\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary id=\"is-persistent\"\u003eNotify the user when \u003ccode\u003elocalStorage\u003c/code\u003e isn't saving the data using the \u003ccode\u003eisPersistent\u003c/code\u003e property\u003c/summary\u003e\n\u003cp\u003e\u003c/p\u003e\n\nThere are a few cases when `localStorage` [isn't available](https://github.com/astoilkov/use-local-storage-state/blob/7db8872397eae8b9d2421f068283286847f326ac/index.ts#L3-L11). The `isPersistent` property tells you if the data is persisted in `localStorage` or in-memory. Useful when you want to notify the user that their data won't be persisted.\n\n```tsx\nimport React, { useState } from 'react'\nimport useLocalStorageState from 'use-local-storage-state'\n\nexport default function Todos() {\n    const [todos, setTodos, { isPersistent }] = useLocalStorageState('todos', {\n        defaultValue: ['buy avocado']\n    })\n\n    return (\n        \u003c\u003e\n            {todos.map(todo =\u003e (\u003cdiv\u003e{todo}\u003c/div\u003e))}\n            {!isPersistent \u0026\u0026 \u003cspan\u003eChanges aren't currently persisted.\u003c/span\u003e}\n        \u003c/\u003e\n    )\n}\n\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary id=\"remove-item\"\u003eRemoving the data from \u003ccode\u003elocalStorage\u003c/code\u003e and resetting to the default\u003c/summary\u003e\n\u003cp\u003e\u003c/p\u003e\n\nThe `removeItem()` method will reset the value to its default and will remove the key from the `localStorage`. It returns to the same state as when the hook was initially created.\n\n```tsx\nimport useLocalStorageState from 'use-local-storage-state'\n\nexport default function Todos() {\n    const [todos, setTodos, { removeItem }] = useLocalStorageState('todos', {\n        defaultValue: ['buy avocado']\n    })\n\n    function onClick() {\n        removeItem()\n    }\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eWhy my component renders twice?\u003c/summary\u003e\n\u003cp\u003e\u003c/p\u003e\n\nIf you are hydrating your component (for example, if you are using Next.js), your component might re-render twice. This is behavior specific to React and not to this library. It's caused by the `useSyncExternalStore()` hook. There is no workaround. This has been discussed in the issues: https://github.com/astoilkov/use-local-storage-state/issues/56.\n\nIf you want to know if you are currently rendering the server value you can use this helper function:\n```ts\nfunction useIsServerRender() {\n  return useSyncExternalStore(() =\u003e {\n    return () =\u003e {}\n  }, () =\u003e false, () =\u003e true)\n}\n```\n\n\u003c/details\u003e\n\n## API\n\n#### `useLocalStorageState(key: string, options?: LocalStorageOptions)`\n\nReturns `[value, setValue, { removeItem, isPersistent }]` when called. The first two values are the same as `useState()`. The third value contains two extra properties:\n- `removeItem()` — calls `localStorage.removeItem(key)` and resets the hook to it's default state\n- `isPersistent` — `boolean` property that returns `false` if `localStorage` is throwing an error and the data is stored only in-memory\n\n#### `key`\n\nType: `string`\n\nThe key used when calling `localStorage.setItem(key)` and `localStorage.getItem(key)`.\n\n⚠️ Be careful with name conflicts as it is possible to access a property which is already in `localStorage` that was created from another place in the codebase or in an old version of the application.\n\n#### `options.defaultValue`\n\nType: `any`\n\nDefault: `undefined`\n\nThe default value. You can think of it as the same as `useState(defaultValue)`.\n\n#### `options.defaultServerValue`\n\nType: `any`\n\nDefault: `undefined`\n\nThe default value while server-rendering and hydrating. If not set, it will use `defaultValue` option instead. Set only if you want it to be different than the client value.\n\n#### `options.storageSync`\n\nType: `boolean`\n\nDefault: `true`\n\nSetting to `false` doesn't subscribe to the [Window storage event](https://developer.mozilla.org/en-US/docs/Web/API/Window/storage_event). If you set to `false`, updates won't be synchronized across tabs, windows and iframes.\n\n#### `options.serializer`\n\nType: `{ stringify, parse }`\n\nDefault: `JSON`\n\nJSON does not serialize `Date`, `Regex`, or `BigInt` data.  You can pass in [superjson](https://github.com/blitz-js/superjson) or other `JSON`-compatible serialization library for more advanced serialization.\n\n## Related\n\n- [`use-storage-state`](https://github.com/astoilkov/use-storage-state) — Supports `localStorage`, `sessionStorage`, and any other [`Storage`](https://developer.mozilla.org/en-US/docs/Web/API/Storage) compatible API.\n- [`use-session-storage-state`](https://github.com/astoilkov/use-session-storage-state) — A clone of this library but for `sessionStorage`.\n- [`use-db`](https://github.com/astoilkov/use-db) — Similar to this hook but for `IndexedDB`.\n- [`local-db-storage`](https://github.com/astoilkov/local-db-storage) — Tiny wrapper around `IndexedDB` that mimics `localStorage` API.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fastoilkov%2Fuse-local-storage-state","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fastoilkov%2Fuse-local-storage-state","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fastoilkov%2Fuse-local-storage-state/lists"}