{"id":28392048,"url":"https://github.com/rajtoshranjan/use-idb-store","last_synced_at":"2026-03-10T01:31:12.109Z","repository":{"id":293886331,"uuid":"985361371","full_name":"rajtoshranjan/use-idb-store","owner":"rajtoshranjan","description":"A React state hook that syncs state to IndexedDB for persistent, offline-friendly, and large-scale data storage.","archived":false,"fork":false,"pushed_at":"2025-05-25T12:36:48.000Z","size":170,"stargazers_count":0,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-09-14T21:59:22.545Z","etag":null,"topics":["frontend","indexeddb","library","react","react-hook","typescript","ui","use-idb-store"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/use-idb-store","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/rajtoshranjan.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,"zenodo":null}},"created_at":"2025-05-17T15:47:46.000Z","updated_at":"2025-05-25T12:36:52.000Z","dependencies_parsed_at":"2025-05-17T18:48:21.804Z","dependency_job_id":"66e10279-060e-4b1d-8c94-a87c3ed4f469","html_url":"https://github.com/rajtoshranjan/use-idb-store","commit_stats":null,"previous_names":["rajtoshranjan/use-idb-store","rajtoshranjan/use-indexeddb-state"],"tags_count":17,"template":false,"template_full_name":null,"purl":"pkg:github/rajtoshranjan/use-idb-store","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rajtoshranjan%2Fuse-idb-store","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rajtoshranjan%2Fuse-idb-store/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rajtoshranjan%2Fuse-idb-store/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rajtoshranjan%2Fuse-idb-store/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rajtoshranjan","download_url":"https://codeload.github.com/rajtoshranjan/use-idb-store/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rajtoshranjan%2Fuse-idb-store/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30320886,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-09T20:05:46.299Z","status":"ssl_error","status_checked_at":"2026-03-09T19:57:04.425Z","response_time":61,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["frontend","indexeddb","library","react","react-hook","typescript","ui","use-idb-store"],"created_at":"2025-05-31T11:14:34.597Z","updated_at":"2026-03-10T01:31:12.029Z","avatar_url":"https://github.com/rajtoshranjan.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# use-idb-store\n\nA React hook that provides persistent state management using IndexedDB, offering offline-friendly and large-scale data storage capabilities.\n\n[![npm version](https://img.shields.io/npm/v/use-idb-store.svg)](https://www.npmjs.com/package/use-idb-store)\n[![license](https://img.shields.io/npm/l/use-idb-store.svg)](https://github.com/rajtoshranjan/use-idb-store/blob/master/LICENSE)\n[![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)\n\n## Features\n\n- 💾 **Persistent State:** Automatically syncs React state with IndexedDB\n- 🔌 **Offline Support:** Data persists even when offline\n- 📦 **Large Data Sets:** Handles much larger data than localStorage\n- 🔄 **CRUD Operations:** Full API for creating, reading, updating, and deleting data\n- 🛠️ **TypeScript Ready:** Full type safety with generics support\n- 🏗️ **Robust Error Handling:** Gracefully handles edge cases\n- 🧩 **Zero Dependencies:** Lightweight with no external dependencies\n- 🌐 **Global Store Behavior:** When you use the same store name across different components, they all share the same store instance and data\n\n## [Demo App](https://use-idb-store.rajtoshranjan.dev/#demo)\n\n## Installation\n\n```bash\nnpm install use-idb-store\n# or\nyarn add use-idb-store\n# or\npnpm add use-idb-store\n```\n\n## Quick Start\n\n```jsx\nimport { useIndexedDbStore } from \"use-idb-store\";\n\nfunction TodoApp() {\n  // Initialize the store with a name\n  const { values, mutations, isLoading, isReady, error } =\n    useIndexedDbStore(\"todos\");\n\n  // Access your persisted data\n  const todos = Object.values(values);\n\n  // Add a new item\n  const addTodo = (text) =\u003e {\n    const id = Date.now().toString();\n    mutations.addValue(id, { id, text, completed: false });\n  };\n\n  // Toggle a todo's completed status\n  const toggleTodo = (id) =\u003e {\n    const todo = values[id];\n    mutations.updateValue(id, { completed: !todo.completed });\n  };\n\n  // Delete a todo\n  const removeTodo = (id) =\u003e {\n    mutations.deleteValue(id);\n  };\n\n  if (isLoading) return \u003cdiv\u003eLoading...\u003c/div\u003e;\n  if (error) return \u003cdiv\u003eError: {error.message}\u003c/div\u003e;\n\n  return (\n    \u003cdiv\u003e\n      \u003ch1\u003eTodo List\u003c/h1\u003e\n      \u003cbutton onClick={() =\u003e addTodo(\"New Todo\")}\u003eAdd Todo\u003c/button\u003e\n      \u003cul\u003e\n        {todos.map((todo) =\u003e (\n          \u003cli key={todo.id}\u003e\n            \u003cinput\n              type=\"checkbox\"\n              checked={todo.completed}\n              onChange={() =\u003e toggleTodo(todo.id)}\n            /\u003e\n            \u003cspan\u003e{todo.text}\u003c/span\u003e\n            \u003cbutton onClick={() =\u003e removeTodo(todo.id)}\u003eDelete\u003c/button\u003e\n          \u003c/li\u003e\n        ))}\n      \u003c/ul\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n## API Reference\n\n### `useIndexedDbStore\u003cT\u003e(name, options)`\n\nThe main hook for creating and interacting with an IndexedDB store.\n\n#### Parameters\n\n- `name` (string): A unique name for the store. This will be used as the IndexedDB object store name.\n- `options` (object, optional):\n  - `schema` (IDBObjectStoreParameters, optional): Schema configuration for the IndexedDB store.\n\n#### Returns\n\nAn object with the following properties:\n\n- `values` (Record\u003cstring, T\u003e): An object containing all key-value pairs in the store.\n- `mutations`: Object containing methods to mutate the store:\n  - `getValue(id)`: Get a single value by key.\n  - `addValue(id, value)`: Add a new value to the store.\n  - `updateValue(id, partialValue)`: Update part of an existing value.\n  - `deleteValue(id)`: Delete a value by key.\n  - `addOrUpdateValue(id, value)`: Add a value or update it if it already exists.\n- `isLoading` (boolean): Indicates if the store is currently in a loading state, which occurs during initial data fetch from IndexedDB or refetching the data after any mutation.\n- `isReady` (boolean): Indicates if the store has been fully initialized and synchronized with IndexedDB, meaning all initial data has been loaded and the store is ready to perform operations. This flag becomes true only after the initial successful data load.\n- `error` (Error | null): Any error that occurred during store operations.\n\n## Advanced Usage\n\n### Custom Schema\n\nYou can configure your IndexedDB store schema:\n\n```jsx\nconst { values, mutations } = useIndexedDbStore(\"users\", {\n  schema: { keyPath: \"userId\", autoIncrement: true },\n});\n```\n\n### Type Safety\n\nTypeScript users can specify the data type:\n\n```tsx\ninterface User {\n  id: string;\n  name: string;\n  email: string;\n  age: number;\n}\n\nconst { values, mutations } = useIndexedDbStore\u003cUser\u003e(\"users\");\n\n// Type-safe operations\nmutations.addValue(\"user1\", {\n  id: \"user1\",\n  name: \"John Doe\",\n  email: \"john@example.com\",\n  age: 30,\n});\n```\n\n### Global Store Behavior\n\nOne of the most powerful features of `use-idb-store` is its **automatic global store behavior**. When you use the same store name across different components, they all share the same store instance and data. This eliminates the need for prop drilling or React Context for shared state.\n\n#### How It Works\n\n```jsx\n// Component A\nfunction TodoList() {\n  const { values: todos, mutations } = useIndexedDbStore(\"todos\");\n\n  return (\n    \u003cdiv\u003e\n      \u003ch2\u003eTodo List ({Object.keys(todos).length} items)\u003c/h2\u003e\n      {Object.values(todos).map((todo) =\u003e (\n        \u003cdiv key={todo.id}\u003e{todo.text}\u003c/div\u003e\n      ))}\n    \u003c/div\u003e\n  );\n}\n\n// Component B (completely separate)\nfunction TodoForm() {\n  const { mutations } = useIndexedDbStore(\"todos\"); // Same store name!\n\n  const addTodo = () =\u003e {\n    const id = Date.now().toString();\n    mutations.addValue(id, {\n      id,\n      text: \"New todo from form\",\n      completed: false,\n    });\n  };\n\n  return \u003cbutton onClick={addTodo}\u003eAdd Todo\u003c/button\u003e;\n}\n\n// Component C (in a different part of your app)\nfunction TodoStats() {\n  const { values: todos } = useIndexedDbStore(\"todos\"); // Same store again!\n\n  const completedCount = Object.values(todos).filter(\n    (todo) =\u003e todo.completed\n  ).length;\n\n  return \u003cp\u003eCompleted: {completedCount}\u003c/p\u003e;\n}\n```\n\n#### Key Benefits\n\n- **🌐 Global State**: No need for Context providers or prop drilling\n- **🔄 Real-time Sync**: Changes in one component instantly reflect in all others\n- **💾 Persistent**: Data persists across page reloads and browser sessions\n- **🎯 Isolated**: Different store names remain completely separate\n\n#### Multiple Stores Example\n\nYou can use multiple independent stores throughout your application:\n\n```jsx\nfunction UserProfile() {\n  const { values: users } = useIndexedDbStore(\"users\");\n  const { values: settings } = useIndexedDbStore(\"settings\");\n  const { values: todos } = useIndexedDbStore(\"todos\");\n\n  // Each store is independent but globally accessible\n  return (\n    \u003cdiv\u003e\n      \u003ch1\u003eWelcome {users.currentUser?.name}\u003c/h1\u003e\n      \u003cp\u003eTheme: {settings.theme}\u003c/p\u003e\n      \u003cp\u003ePending todos: {Object.keys(todos).length}\u003c/p\u003e\n    \u003c/div\u003e\n  );\n}\n\nfunction SettingsPanel() {\n  const { mutations } = useIndexedDbStore(\"settings\"); // Same settings store\n\n  const toggleTheme = () =\u003e {\n    mutations.updateValue(\"theme\", { value: \"dark\" });\n  };\n\n  return \u003cbutton onClick={toggleTheme}\u003eToggle Theme\u003c/button\u003e;\n}\n```\n\n#### Best Practices\n\n1. **Consistent Naming**: Use descriptive, consistent store names across your app\n2. **Type Definitions**: Define TypeScript interfaces for better development experience\n3. **Store Separation**: Keep different data types in separate stores for better organization\n\n```tsx\n// Good: Organized by data type\nconst { values: users } = useIndexedDbStore\u003cUser\u003e(\"users\");\nconst { values: todos } = useIndexedDbStore\u003cTodo\u003e(\"todos\");\nconst { values: settings } = useIndexedDbStore\u003cSettings\u003e(\"app-settings\");\n\n// Avoid: Mixing unrelated data in one store\nconst { values: mixedData } = useIndexedDbStore(\"everything\"); // Not recommended\n```\n\n### Error Handling\n\nThe hook provides built-in error handling:\n\n```jsx\nconst { values, mutations, error, isLoading } = useIndexedDbStore(\"data\");\n\n// Display loading state and errors in your UI\nif (isLoading) return \u003cdiv\u003eLoading...\u003c/div\u003e;\nif (error) return \u003cdiv\u003eError: {error.message}\u003c/div\u003e;\n\n// You can also handle errors from individual operations\nconst handleAddItem = async () =\u003e {\n  try {\n    await mutations.addValue(\"key1\", { name: \"New Item\" });\n  } catch (err) {\n    console.error(\"Failed to add item:\", err);\n  }\n};\n```\n\n## How It Works\n\n`use-idb-store` uses a layered architecture:\n\n1. **Hook Layer** (`useIndexedDbStore`): React hook that provides a state interface\n2. **Store Layer** (`Store`): Manages data operations on a specific IndexedDB object store\n3. **Database Layer** (`DB`): Handles IndexedDB connections and versioning\n4. **Utilities** (`helpers`): Provides utility functions for working with IndexedDB promises\n\nThe library automatically handles common IndexedDB challenges:\n\n- Database versioning and schema upgrades\n- Async request management with Promises\n- Error recovery and connection management\n\n## Browser Compatibility\n\nThis library works in all modern browsers that support IndexedDB:\n\n- Chrome 24+\n- Firefox 16+\n- Safari 10+\n- Edge 12+\n- Opera 15+\n\n## License\n\nMIT © [Rajtosh Ranjan](https://github.com/rajtoshranjan)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frajtoshranjan%2Fuse-idb-store","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frajtoshranjan%2Fuse-idb-store","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frajtoshranjan%2Fuse-idb-store/lists"}