{"id":15275825,"url":"https://github.com/abians/zustand-debounce","last_synced_at":"2025-08-31T22:38:47.393Z","repository":{"id":200832137,"uuid":"706357102","full_name":"AbianS/zustand-debounce","owner":"AbianS","description":"zustand-debounce is a library that extends the capabilities of Zustand to provide a JSON state storage system with delayed (debounced) writing to storage.","archived":false,"fork":false,"pushed_at":"2025-02-07T09:30:06.000Z","size":342,"stargazers_count":15,"open_issues_count":2,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-08-09T19:49:25.853Z","etag":null,"topics":["debounce","react","reactjs","zustand","zustand-debounce","zustand-persist"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/zustand-debounce","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AbianS.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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}},"created_at":"2023-10-17T19:37:39.000Z","updated_at":"2025-04-20T13:56:45.000Z","dependencies_parsed_at":null,"dependency_job_id":"c5b1e98d-2267-41b9-84d1-d130732b83a7","html_url":"https://github.com/AbianS/zustand-debounce","commit_stats":{"total_commits":13,"total_committers":1,"mean_commits":13.0,"dds":0.0,"last_synced_commit":"1b5caa24c84c3479512d3d24009eef0b7131757d"},"previous_names":["abians/zustand-debounce"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/AbianS/zustand-debounce","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AbianS%2Fzustand-debounce","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AbianS%2Fzustand-debounce/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AbianS%2Fzustand-debounce/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AbianS%2Fzustand-debounce/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AbianS","download_url":"https://codeload.github.com/AbianS/zustand-debounce/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AbianS%2Fzustand-debounce/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273051860,"owners_count":25037074,"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","status":"online","status_checked_at":"2025-08-31T02:00:09.071Z","response_time":79,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["debounce","react","reactjs","zustand","zustand-debounce","zustand-persist"],"created_at":"2024-09-30T10:06:45.538Z","updated_at":"2025-08-31T22:38:47.373Z","avatar_url":"https://github.com/AbianS.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Zustand Debounce\n\n**Lightweight** and **powerful** extension for [Zustand](https://github.com/pmndrs/zustand) providing debounced JSON state storage.\n\nZustand Debounce enhances the capabilities of Zustand by introducing a debounced JSON state storage system. By delaying and grouping write operations to storage, you can significantly reduce the number of write operations, improving performance and efficiency in your applications.\n\n## 🚀 Features\n\n✅ **Ultra Lightweight:** Only 1.19 kB gzipped 🐙\n\n✅ **Easy Integration:** Seamlessly integrates into your existing projects 🚀\n\n✅ **Customizable Debounce Time:** Adjust the debounce time to suit your needs ⏳\n\n✅ **Reduced Write Operations:** Avoid frequent writes to storage, optimizing performance 🔄\n\n✅ **Retry Mechanism:** Automatically retries failed write operations with customizable settings 🔁\n\n✅ **Advanced Retry with Exponential Backoff:** Configure exponential backoff with `maxRetries`, `retryDelay`, and `backoffMultiplier` for more resilient retries 📈\n\n✅ **Multiple Storage Adapters:** Choose between `'localStorage'`, `'sessionStorage'`, or `'memoryStorage'` adapters 🗄️\n\n✅ **Extended Event System:** Additional events like `onFlush`, `onRetry`, and `onError` for better control 🎣\n\n✅ **TTL Support:** Specify a Time-To-Live for stored data ⌛\n\n✅ **Custom Serialization:** Use custom serialization and deserialization functions 🛠️\n\n✅ **Full TypeScript Support:** Fully typed for TypeScript projects 📘\n\n## 📦 Installation\n\n```bash\n# Using npm\nnpm install zustand-debounce\n\n# Using yarn\nyarn add zustand-debounce\n\n# Using pnpm\npnpm add zustand-debounce\n```\n\n## 📖 Table of Contents\n\n- [🔧 Usage](#-usage)\n- [⚙️ Options](#️-options)\n- [🌟 Advanced Usage](#-advanced-usage)\n- [🤝 Contributing](#-contributing)\n- [📄 License](#-license)\n- [💬 Support](#-support)\n\n## 🔧 Usage\n\nTo start using Zustand Debounce, replace createJSONStorage with createDebouncedJSONStorage in your Zustand store setup. This will enable delayed writes to your storage.\n\n```ts\nimport { create } from 'zustand';\nimport { persist } from 'zustand/middleware';\nimport { createDebouncedJSONStorage } from 'zustand-debounce';\n\n// Your store interface\ninterface PersonState {\n  name: string;\n  age: number;\n  // Other state properties\n}\n\ninterface Actions {\n  setName: (name: string) =\u003e void;\n  setAge: (age: number) =\u003e void;\n  // Other actions\n}\n\n// Create the store\nexport const usePersonStore = create\u003cPersonState \u0026 Actions\u003e()(\n  persist(\n    (set) =\u003e ({\n      // Initial state\n      name: '',\n      age: 0,\n      // Actions\n      setName: (name) =\u003e set({ name }),\n      setAge: (age) =\u003e set({ age }),\n    }),\n    {\n      name: 'person-storage',\n      storage: createDebouncedJSONStorage('localStorage', {\n        debounceTime: 2000, // Debounce time in milliseconds ⏳\n        // Other options can be specified here\n      }),\n    }\n  )\n);\n```\n\nWith the above setup, changes to the store will be saved to the storage after a 2-second delay, grouping multiple rapid changes into a single write operation.\n\n---\n\n\n## ⚙️ Options\n\ncreateDebouncedJSONStorage accepts a variety of options to customize its behavior:\n\n| **Option**           | **Type**                              | **Default**       | **Description**                                                                                                                                                                                                                     |\n|---------------------|---------------------------------------|-------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `debounceTime`      | `number`                              | `0`               | The debounce time in milliseconds. Write operations will be delayed by this amount of time. If multiple writes occur within this period, they will be grouped into a single write.                                                  |\n| `throttleTime`      | `number`                              | `0`               | The throttle time in milliseconds. Ensures that write operations are not performed more frequently than this interval.                                                                                                               |\n| `immediately`       | `boolean`                             | `false`           | If set to `true`, write operations will occur immediately without any delay.                                                                                                                                                        |\n| `maxRetries`        | `number`                              | `0`               | The maximum number of times to retry a failed write operation.                                                                                                                                                                      |\n| `retryDelay`        | `number`                              | `0`               | The delay in milliseconds between retry attempts for failed write operations.                                                                                                                                                       |\n| `backoffMultiplier` | `number`                              | `1`               | The multiplier used for exponential backoff between retry attempts. Each retry will wait `retryDelay * (backoffMultiplier ^ attempt)` milliseconds.                                                                                  |\n| `onWrite`           | `(key: string, value: string) =\u003e void` | `undefined`       | A callback function that is called immediately when `setItem` is invoked, before the debounce delay.                                                                                                                                |\n| `onSave`            | `(key: string, value: string) =\u003e void` | `undefined`       | A callback function that is called after the debounce delay when the data is actually saved to storage.                                                                                                                             |\n| `onFlush`           | `(key: string, value: string) =\u003e void` | `undefined`       | A callback function that is called when a manual flush operation is executed.                                                                                                                                                      |\n| `onRetry`           | `(key: string, attempt: number, error: any, delay: number) =\u003e void` | `undefined` | A callback function that is called before each retry attempt, providing information about the retry attempt number, the error that occurred, and the delay before the next attempt.                                    |\n| `onError`           | `(key: string, error: any) =\u003e void`    | `undefined`       | A callback function that is called when all retry attempts have failed.                                                                                                                                                            |\n| `serialize`         | `(state: unknown) =\u003e string`           | `JSON.stringify`  | A custom function to serialize the state before saving it to storage.                                                                                                                                                               |\n| `deserialize`       | `(str: string) =\u003e unknown`             | `JSON.parse`      | A custom function to deserialize the state after retrieving it from storage.                                                                                                                                                        |\n| `ttl`               | `number`                              | `0`               | Time-to-live in milliseconds for the stored data. After this period, the data will be considered expired and removed from storage.                                                                                                  |\n\n\n## 🌟 Advanced Usage\n\nHere is an example demonstrating the use of multiple options:\n\n```ts\nimport { createDebouncedJSONStorage } from 'zustand-debounce';\n\n// Example with localStorage\nconst localStorageExample = createDebouncedJSONStorage('localStorage', {\n  debounceTime: 1000, // Delay write operations by 1 second\n  throttleTime: 5000, // Ensure writes are at least 5 seconds apart\n  immediately: false, // Do not write immediately\n  maxRetries: 3, // Retry failed writes up to 3 times\n  retryDelay: 2000, // Wait 2 seconds between retries\n  ttl: 86400000, // Data expires after 24 hours\n  onWrite: (key, value) =\u003e {\n    console.log(`Write initiated for ${key}`);\n  },\n  onSave: (key, value) =\u003e {\n    console.log(`Data saved for ${key}`);\n  },\n  serialize: (state) =\u003e {\n    // Custom serialization logic\n    return JSON.stringify(state);\n  },\n  deserialize: (str) =\u003e {\n    // Custom deserialization logic\n    return JSON.parse(str);\n  },\n});\n\n// Example with sessionStorage and advanced retry + events\nconst sessionStorageExample = createDebouncedJSONStorage('sessionStorage', {\n  debounceTime: 500,\n  maxRetries: 3,\n  retryDelay: 1000,\n  backoffMultiplier: 2, // Each retry will wait longer: 1s, 2s, 4s\n  onRetry: (key, attempt, error, delay) =\u003e {\n    console.log(`Retry ${attempt} for ${key} after ${delay}ms. Error: ${error.message}`);\n  },\n  onError: (key, error) =\u003e {\n    console.error(`All retries failed for ${key}:`, error);\n  },\n  onFlush: (key, value) =\u003e {\n    console.log(`Manual flush executed for ${key}`);\n  }\n});\n\n// Example with in-memory storage\nconst memoryStorageExample = createDebouncedJSONStorage('memoryStorage', {\n  debounceTime: 100,\n  immediately: true\n});\n\n// Example with custom storage adapter\nconst customStorageExample = createDebouncedJSONStorage({\n  getItem: async (key: string) =\u003e {\n    // Implement your custom get logic here\n    return await myCustomDatabase.get(key);\n  },\n  setItem: async (key: string, value: string) =\u003e {\n    // Implement your custom set logic here\n    await myCustomDatabase.set(key, value);\n  },\n  removeItem: async (key: string) =\u003e {\n    // Implement your custom remove logic here\n    await myCustomDatabase.delete(key);\n  }\n}, {\n  debounceTime: 1000,\n  maxRetries: 3,\n  retryDelay: 1000,\n  backoffMultiplier: 2\n});\n```\n\n## 🔧 Creating Custom Storage Adapters\n\nYou can create your own storage adapter by implementing the `StateStorage` interface. This allows you to integrate any storage solution with Zustand Debounce:\n\n```ts\ninterface StateStorage {\n  getItem: (key: string) =\u003e Promise\u003cstring | null\u003e | string | null;\n  setItem: (key: string, value: string) =\u003e Promise\u003cvoid\u003e | void;\n  removeItem: (key: string) =\u003e Promise\u003cvoid\u003e | void;\n}\n\n// Example: Custom IndexedDB adapter\nconst createIndexedDBAdapter = (dbName: string, storeName: string): StateStorage =\u003e {\n  // Open IndexedDB connection\n  const dbPromise = indexedDB.open(dbName, 1);\n  \n  dbPromise.onupgradeneeded = (event) =\u003e {\n    const db = event.target.result;\n    db.createObjectStore(storeName);\n  };\n\n  return {\n    async getItem(key) {\n      const db = await dbPromise;\n      const transaction = db.transaction(storeName, 'readonly');\n      const store = transaction.objectStore(storeName);\n      return await store.get(key);\n    },\n    async setItem(key, value) {\n      const db = await dbPromise;\n      const transaction = db.transaction(storeName, 'readwrite');\n      const store = transaction.objectStore(storeName);\n      await store.put(value, key);\n    },\n    async removeItem(key) {\n      const db = await dbPromise;\n      const transaction = db.transaction(storeName, 'readwrite');\n      const store = transaction.objectStore(storeName);\n      await store.delete(key);\n    }\n  };\n};\n\n// Use your custom adapter\nconst customDBStorage = createDebouncedJSONStorage(\n  createIndexedDBAdapter('myDB', 'zustand-store'),\n  {\n    debounceTime: 1000,\n    // ... other options\n  }\n);\n```\n\n## 🤝 Contributing\n\nContributions are welcome! If you have ideas for improvements or have found a bug, please open an issue or submit a pull request.\n\n1. **Fork the repository**\n2. **Create a new branch:** git checkout -b feature/your-feature-name\n3. **Make your changes** and commit them: git commit -m 'Add some feature'\n4. **Push to the branch:** git push origin feature/your-feature-name\n5. **Open a pull request**\n\nPlease ensure your code follows the project's coding standards and includes appropriate tests.\n\n## 📄 License\n\nThis project is licensed under the MIT License - see the LICENSE file for details.\n\n## 💬 Support\n\nIf you find this project useful, please consider giving it a ⭐ on GitHub. If you have any questions or need support, feel free to open an issue or contact me.\n\n\u003chr /\u003e\n\n\u003cp align=\"center\" style=\"text-align:center\"\u003ewith 💖 by \u003ca href=\"https://github.com/AbianS\" target=\"_blank\"\u003eAbianS\u003c/a\u003e\u003c/p\u003e","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fabians%2Fzustand-debounce","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fabians%2Fzustand-debounce","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fabians%2Fzustand-debounce/lists"}