{"id":16696588,"url":"https://github.com/karolis-sh/use-optimistic-update","last_synced_at":"2025-04-10T02:41:49.083Z","repository":{"id":38336801,"uuid":"255698419","full_name":"karolis-sh/use-optimistic-update","owner":"karolis-sh","description":"Optimistic UI utilities","archived":false,"fork":false,"pushed_at":"2023-10-27T07:09:03.000Z","size":1511,"stargazers_count":6,"open_issues_count":3,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-21T08:46:11.584Z","etag":null,"topics":["hooks","optimistic-ui","optimistic-updates","perceived-performance","react"],"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/karolis-sh.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","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}},"created_at":"2020-04-14T18:55:33.000Z","updated_at":"2023-11-28T07:25:27.000Z","dependencies_parsed_at":"2025-02-16T10:32:45.858Z","dependency_job_id":"5240f926-6a20-4e13-95d1-80da0dc07a47","html_url":"https://github.com/karolis-sh/use-optimistic-update","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/karolis-sh%2Fuse-optimistic-update","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/karolis-sh%2Fuse-optimistic-update/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/karolis-sh%2Fuse-optimistic-update/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/karolis-sh%2Fuse-optimistic-update/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/karolis-sh","download_url":"https://codeload.github.com/karolis-sh/use-optimistic-update/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248144957,"owners_count":21055015,"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":["hooks","optimistic-ui","optimistic-updates","perceived-performance","react"],"created_at":"2024-10-12T17:44:13.385Z","updated_at":"2025-04-10T02:41:49.065Z","avatar_url":"https://github.com/karolis-sh.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# use-optimistic-update\n\n[![npm version][version-badge]][version]\n[![gzip size][size-badge]][size]\n![Node.js CI](https://github.com/karolis-sh/use-optimistic-update/workflows/Node.js%20CI/badge.svg)\n[![License: MIT][license-badge]][license]\n[![code style: prettier][code-style-badge]][code-style]\n\n\u003e Improve perceived performance by predicting the future outcome\n\nA set of utilities to achieve **Optimistic UI** effect. Helps to bridge the gap\nbetween async state changes.\n\n## Example\n\nConverting async counter to optimistic component that reacts to user actions instantly:\n\n```diff\n  import React, { useState } from 'react';\n+ import { useOptimisticUpdate } from \"use-optimistic-update\";\n\n  export default function UpTo3Counter() {\n    const [counter, setCounter] = useState(0);\n+   const { value, onUpdate } = useOptimisticUpdate(\"count3r\", counter);\n\n    const increment = (value) =\u003e\n      new Promise((resolve) =\u003e {\n        setTimeout(() =\u003e {\n          if (value \u003c= 3) setCounter(value);\n          resolve();\n        }, 1000);\n      });\n\n    return (\n      \u003cbutton\n        onClick={() =\u003e {\n          const newValue = counter + 1;\n-         increment(newValue);\n+         onUpdate(() =\u003e increment(newValue), newValue);\n        }}\n      \u003e\n-       Likes: {counter}\n+       Likes: {value}\n      \u003c/button\u003e\n    );\n  }\n```\n\n## Installation\n\n`npm i use-optimistic-update`\n\nor\n\n`yarn add use-optimistic-update`\n\n## Features\n\n- shareable state between multiple components\n- hooks\n- direct event emitter access\n- typescript support\n\n## API\n\n- [use-optimistic-update](#use-optimistic-update)\n  - [Example](#example)\n  - [Installation](#installation)\n  - [Features](#features)\n  - [API](#api)\n    - [`useOptimisticUpdate`](#useoptimisticupdate)\n    - [`useOptimisticState`](#useoptimisticstate)\n    - [`optimist`](#optimist)\n      - [`optimist.sync`](#optimistsync)\n      - [`optimist.update`](#optimistupdate)\n        - [Using `optimist.update`](#using-optimistupdate)\n      - [`optimist.getState`](#optimistgetstate)\n      - [`optimist.onUpdate`](#optimistonupdate)\n  - [FAQ](#faq)\n  - [License](#license)\n\n### `useOptimisticUpdate`\n\n`useOptimisticUpdate` is a hook that let's you sync and update the optimistic state.\n\n```jsx\nimport { useOptimisticUpdate } from 'use-optimistic-update';\n\nconst { value, onUpdate, isUpdating } = useOptimisticUpdate(\n  stateKey,\n  realValue,\n);\n```\n\nOptions\n\n- `stateKey: string`\n  - **Required**\n- `realValue: string | number | boolean | undefined`\n  - **Required**\n\nReturns\n\n- `value: string | number | boolean | undefined`\n\n  - The optimistic value\n\n\u003c!-- markdownlint-disable line-length --\u003e\n\n- ```ts\n  onUpdate: (\n    updater: () =\u003e Promise\u003cvoid\u003e,\n    newValue: string | number | boolean | undefined,\n  ) =\u003e Promise\u003cvoid\u003e;\n  ```\n\n  \u003c!-- markdownlint-enable line-length --\u003e\n\n  - Updater function that should be called when you want to update **real** and **optimistic**\n    values\n  - `updater`\n    - Async function that should perform the **real** value change\n    - While this function is executing the optimistic value is perceived\n  - `newValue`\n    - The new **optimistic** value\n\n- `isUpdating: boolean`\n  - Is an update being performed for given `stateKey`\n\n#### Using `onUpdate` function\n\n```jsx\n\u003cbutton\n  className={}\n  onClick={() =\u003e {\n    onUpdate(async () =\u003e {\n      await incrementCounter();\n    }, counter + 1);\n  }}\n\u003e\n  {counter}\n\u003c/button\u003e\n```\n\n### `useOptimisticState`\n\n`useOptimisticState` is a hook that let's you retrieve the optimistic state.\n\n```jsx\nimport { useOptimisticState } from 'use-optimistic-update';\n\nconst { value, isUpdating } = useOptimisticState(stateKey);\n```\n\nOptions\n\n- `stateKey: string`\n  - **Required**\n\nReturns\n\n- `value: string | number | boolean | undefined`\n  - The optimistic value\n- `isUpdating: boolean`\n  - Is an update being performed for given `stateKey`\n\n### `optimist`\n\n`optimist` is the underlying event emitter used by the hooks. It is responsible\nfor updating / syncing of optimistic / real values.\n\n#### `optimist.sync`\n\nSynchronize the real value with `optimist` instance.\n\n```jsx\nimport { optimist } from 'use-optimistic-update';\n\noptimist.sync(stateKey, realValue);\n```\n\nOptions\n\n- `stateKey: string`\n  - **Required**\n- `realValue: string | number | boolean | undefined`\n  - **Required**\n\n#### `optimist.update`\n\nUpdate optimistic value inside the `optimist` instance.\n\n```jsx\nimport { optimist } from 'use-optimistic-update';\n\noptimist.update(stateKey, updater, optimisticValue);\n```\n\nOptions\n\n- `stateKey: string`\n  - **Required**\n- `updater: () =\u003e Promise\u003cvoid\u003e`\n  - **Required**\n- `optimisticValue: string | number | boolean | undefined`\n  - **Required**\n\n##### Using `optimist.update`\n\n```jsx\nimport { optimist } from 'use-optimistic-update';\n\noptimist.update(\n  'count3r',\n  async () =\u003e {\n    await incrementCounter();\n  },\n  counter + 1,\n);\n```\n\n#### `optimist.getState`\n\nRetrieve the optimistic state.\n\n```jsx\nimport { optimist } from 'use-optimistic-update';\n\nconst { value, isUpdating } = optimist.getState(stateKey);\n```\n\nOptions\n\n- `stateKey: string`\n  - **Required**\n\nReturns\n\n- `value: string | number | boolean | undefined`\n  - The optimistic value\n- `isUpdating: boolean`\n  - Is an update being performed for given `stateKey`\n\n#### `optimist.onUpdate`\n\nRetrieve the optimistic state.\n\n```jsx\nimport { optimist } from 'use-optimistic-update';\n\nconst unbind = optimist.onUpdate(stateKey, listener);\n```\n\nOptions\n\n- `stateKey: string`\n\n  - **Required**\n\n- ```ts\n  listener: ({\n    value: string | number | boolean | undefined;\n    isUpdating: boolean;\n  }) =\u003e void\n  ```\n\n  - **Required**\n  - The function that will be called every time the optimistic state changes\n\nReturns\n\n- `unbind: () =\u003e void`\n  - A function to remove the event listener\n\n##### Using `optimist.onUpdate`\n\n```js\nimport { useEffect } from 'react';\nimport { optimist } from 'use-optimistic-update';\n\nuseEffect(() =\u003e {\n  const unbind = optimist.onUpdate('count3r', ({ value, isUpdating }) =\u003e {\n    console.log('count3r changes:', value, isUpdating);\n  });\n  return unbind;\n}, []);\n```\n\n## FAQ\n\n- **_What is Optimistic UI?_**\n\nOptimistic UI is a pattern that you can use to simulate the results of a mutation\nand update the UI even before receiving a response from the server.\n\n## License\n\nMIT\n\n[version-badge]: https://badge.fury.io/js/use-optimistic-update.svg\n[version]: https://www.npmjs.com/package/use-optimistic-update\n[size-badge]: https://img.shields.io/bundlephobia/minzip/use-optimistic-update?label=gzip\n[size]: https://bundlephobia.com/result?p=use-optimistic-update\n[license-badge]: https://img.shields.io/badge/License-MIT-yellow.svg\n[license]: https://opensource.org/licenses/MIT\n[code-style-badge]: https://img.shields.io/badge/code_style-prettier-ff69b4.svg\n[code-style]: https://github.com/prettier/prettier\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkarolis-sh%2Fuse-optimistic-update","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkarolis-sh%2Fuse-optimistic-update","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkarolis-sh%2Fuse-optimistic-update/lists"}