{"id":13429615,"url":"https://github.com/homerchen19/use-undo","last_synced_at":"2026-04-02T12:59:00.951Z","repository":{"id":42126169,"uuid":"156137396","full_name":"homerchen19/use-undo","owner":"homerchen19","description":"React Hooks to implement Undo and Redo functionality","archived":false,"fork":false,"pushed_at":"2023-01-04T02:30:28.000Z","size":747,"stargazers_count":397,"open_issues_count":19,"forks_count":23,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-10-29T18:05:46.610Z","etag":null,"topics":["hooks","react","react-hooks"],"latest_commit_sha":null,"homepage":"https://codesandbox.io/s/use-undo-demo-hifeo","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/homerchen19.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}},"created_at":"2018-11-05T00:03:37.000Z","updated_at":"2024-10-18T00:18:47.000Z","dependencies_parsed_at":"2023-02-01T18:00:46.548Z","dependency_job_id":null,"html_url":"https://github.com/homerchen19/use-undo","commit_stats":null,"previous_names":["xxhomey19/use-undo"],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/homerchen19%2Fuse-undo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/homerchen19%2Fuse-undo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/homerchen19%2Fuse-undo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/homerchen19%2Fuse-undo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/homerchen19","download_url":"https://codeload.github.com/homerchen19/use-undo/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248525770,"owners_count":21118749,"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","react","react-hooks"],"created_at":"2024-07-31T02:00:42.519Z","updated_at":"2026-04-02T12:59:00.940Z","avatar_url":"https://github.com/homerchen19.png","language":"TypeScript","funding_links":[],"categories":["Packages"],"sub_categories":[],"readme":"# ♻️ use-undo\n\nundo/redo functionality with React [Hooks](https://reactjs.org/docs/hooks-intro.html).\n\n\u003cp\u003e\n  \u003ca target=\"_blank\" href=\"https://npmjs.org/package/use-undo\" title=\"NPM version\"\u003e\u003cimg src=\"https://img.shields.io/npm/v/use-undo.svg\"\u003e\u003c/a\u003e\n  \u003ca target=\"_blank\" href=\"http://makeapullrequest.com\" title=\"PRs Welcome\"\u003e\u003cimg src=\"https://img.shields.io/badge/PRs-welcome-brightgreen.svg\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n\u003cimg width=\"1280\" alt=\"screensho\" src=\"https://user-images.githubusercontent.com/12113222/47952303-3c690d80-dfc1-11e8-9df3-7d00443a4487.gif\" /\u003e\n\u003c/p\u003e\n\n## Installation\n\n```sh\nnpm install use-undo\n```\n\n## Usage\n\n[![Edit use-undo-demo](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/use-undo-demo-hifeo?fontsize=14\u0026hidenavigation=1\u0026theme=dark\u0026view=editor)\n\n```js\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport useUndo from 'use-undo';\n\nconst App = () =\u003e {\n  const [\n    countState,\n    {\n      set: setCount,\n      reset: resetCount,\n      undo: undoCount,\n      redo: redoCount,\n      canUndo,\n      canRedo,\n    },\n  ] = useUndo(0);\n  const { present: presentCount } = countState;\n\n  return (\n    \u003cdiv\u003e\n      \u003cp\u003eYou clicked {presentCount} times\u003c/p\u003e\n      \u003cbutton key=\"increment\" onClick={() =\u003e setCount(presentCount + 1)}\u003e\n        +\n      \u003c/button\u003e\n      \u003cbutton key=\"decrement\" onClick={() =\u003e setCount(presentCount - 1)}\u003e\n        -\n      \u003c/button\u003e\n      \u003cbutton key=\"undo\" onClick={undoCount} disabled={!canUndo}\u003e\n        undo\n      \u003c/button\u003e\n      \u003cbutton key=\"redo\" onClick={redoCount} disabled={!canRedo}\u003e\n        redo\n      \u003c/button\u003e\n      \u003cbutton key=\"reset\" onClick={() =\u003e resetCount(0)}\u003e\n        reset to 0\n      \u003c/button\u003e\n    \u003c/div\u003e\n  );\n};\n```\n\n## Manual Checkpoints\n\nManual checkpoints are helpful also when you want manual control over checkpoints. For example it is more helpful when you want to handle input type html tag where value needs to be handled alongside the undo and redo functionality should be handled over some conditions.\n\n```js\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport useUndo from 'use-undo';\n\nconst App = () =\u003e {\n  const [\n    countState,\n    {\n      set: setCount,\n      reset: resetCount,\n      undo: undoCount,\n      redo: redoCount,\n      canUndo,\n      canRedo,\n    },\n  ] = useUndo(0, { useCheckpoints: true });\n  const { present: presentCount } = countState;\n\n  return (\n    \u003cdiv\u003e\n      \u003cp\u003eYou clicked {presentCount} times\u003c/p\u003e\n      \u003cbutton key=\"increment\" onClick={() =\u003e setCount(presentCount + 1, true)}\u003e\n        WithCheckpoint+\n      \u003c/button\u003e\n      \u003cbutton key=\"decrement\" onClick={() =\u003e setCount(presentCount - 1, true)}\u003e\n        WithCheckpoint-\n      \u003c/button\u003e\n      \u003cbutton key=\"increment\" onClick={() =\u003e setCount(presentCount + 1)}\u003e\n        NoCheckpoint+\n      \u003c/button\u003e\n      \u003cbutton key=\"decrement\" onClick={() =\u003e setCount(presentCount - 1)}\u003e\n        NoCheckpoint-\n      \u003c/button\u003e\n      \u003cbutton key=\"undo\" onClick={undoCount} disabled={!canUndo}\u003e\n        undo\n      \u003c/button\u003e\n      \u003cbutton key=\"redo\" onClick={redoCount} disabled={!canRedo}\u003e\n        redo\n      \u003c/button\u003e\n      \u003cbutton key=\"reset\" onClick={() =\u003e resetCount(0)}\u003e\n        reset to 0\n      \u003c/button\u003e\n    \u003c/div\u003e\n  );\n};\n```\n\n## API\n\n### useUndo\n\n```js\nconst [state, actions] = useUndo(initialState);\n```\n\n#### state\n\n##### Type: `Object`\n\n| Key     |  Type   | Description        |\n| ------- | :-----: | ------------------ |\n| past    | `Array` | The undo stack.    |\n| present |  `Any`  | The present state. |\n| future  | `Array` | The redo stack.    |\n\n#### actions\n\n##### Type: `Object`\n\n| Key     |    Type    | Description                                                                                |\n| ------- | :--------: | ------------------------------------------------------------------------------------------ |\n| set     | `function` | Assign a new value to `present`.                                                           |\n| reset   | `function` | Clear `past` array and `future` array. Assign a new value to `present`.                    |\n| undo    | `function` | See [handling-undo](https://redux.js.org/recipes/implementing-undo-history#handling-undo). |\n| redo    | `function` | See [handling-redo](https://redux.js.org/recipes/implementing-undo-history#handling-redo). |\n| canUndo | `boolean`  | Check whether `state.undo.length` is `0`.                                                  |\n| canRedo | `boolean`  | Check whether `state.redo.length` is `0`.                                                  |\n\n## How does it work?\n\nRefer to [_Redux Implementing Undo History_](hhttps://redux.js.org/recipes/implementing-undo-history), `use-undo` implements the same concect with [`useReducer`](https://reactjs.org/docs/hooks-reference.html#usereducer).  \nThe state structure looks like:\n\n```js\n{\n  past: Array\u003cT\u003e,\n  present: \u003cT\u003e,\n  future: Array\u003cT\u003e\n}\n```\n\nIt stores all states we need. To operate on this state, there are three functions in [`actions`](#actions) (`set`, `undo` and `redo`) that dispatch defined types and necessary value.\n\n## Related repo\n\n- [omnidan/redux-undo](https://github.com/omnidan/redux-undo)\n\n## License\n\nMIT © [homerchen19](https://github.com/homerchen19)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhomerchen19%2Fuse-undo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhomerchen19%2Fuse-undo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhomerchen19%2Fuse-undo/lists"}