{"id":13902806,"url":"https://github.com/sergiodxa/use-mutation","last_synced_at":"2025-04-07T15:09:00.967Z","repository":{"id":37095710,"uuid":"281784442","full_name":"sergiodxa/use-mutation","owner":"sergiodxa","description":"🧬 Run side-effects safely in React","archived":false,"fork":false,"pushed_at":"2023-02-17T10:57:47.000Z","size":1345,"stargazers_count":120,"open_issues_count":13,"forks_count":8,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-31T12:06:46.091Z","etag":null,"topics":["hooks","mutations","react-query","reactjs","side-effects","swr","typescript","use-mutation"],"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/sergiodxa.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null},"funding":{"patreon":"sergiodxa","github":"sergiodxa","custom":"https://paypal.me/sergiodxa"}},"created_at":"2020-07-22T21:14:16.000Z","updated_at":"2025-01-24T16:12:16.000Z","dependencies_parsed_at":"2024-01-16T23:31:04.995Z","dependency_job_id":"bfdd138e-9bbd-40e2-a035-505b88498ce3","html_url":"https://github.com/sergiodxa/use-mutation","commit_stats":{"total_commits":166,"total_committers":6,"mean_commits":"27.666666666666668","dds":0.3313253012048193,"last_synced_commit":"2020e1592de9d66842efb65f47e62992293a5747"},"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sergiodxa%2Fuse-mutation","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sergiodxa%2Fuse-mutation/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sergiodxa%2Fuse-mutation/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sergiodxa%2Fuse-mutation/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sergiodxa","download_url":"https://codeload.github.com/sergiodxa/use-mutation/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247675597,"owners_count":20977376,"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","mutations","react-query","reactjs","side-effects","swr","typescript","use-mutation"],"created_at":"2024-08-06T22:01:25.717Z","updated_at":"2025-04-07T15:09:00.941Z","avatar_url":"https://github.com/sergiodxa.png","language":"TypeScript","funding_links":["https://patreon.com/sergiodxa","https://github.com/sponsors/sergiodxa","https://paypal.me/sergiodxa"],"categories":["TypeScript"],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n![🧬 useMutation - Run side-effects safely in React](other/og.png)\n\n\u003c/div\u003e\n\n![CI](https://github.com/sergiodxa/use-mutation/workflows/CI/badge.svg) ![Publish](https://github.com/sergiodxa/use-mutation/workflows/Publish/badge.svg)\n\n\nSpecially useful to run requests against an API, and combined with [SWR](https://swr.vercel.app).\n\n## Usage\n\nInstall it:\n\n```sh\n$ yarn add use-mutation\n```\n\nImport it:\n\n```ts\nimport useMutation from 'use-mutation';\n```\n\nCreate a function which runs a mutation\n\n```tsx\nasync function createComment({\n  authorId,\n  comment,\n}: {\n  authorId: number;\n  comment: string;\n}) {\n  const res = await fetch('/api/comments', {\n    method: 'POST',\n    body: JSON.stringify({ authorId, comment }),\n  });\n  if (!res.ok) throw new Error(res.statusText);\n  return await res.json();\n}\n```\n\nUse your function with `useMutation`\n\n```tsx\nfunction CommentForm({ authorId }) {\n  const [comment, setComment] = React.useState('');\n  const [mutate, { status }] = useMutation(createComment, {\n    onMutate({ input }) {\n      // do something before the mutation run\n      return () =\u003e {\n        // rollback changes if the mutation failed\n      };\n    },\n    onSuccess({ data, input }) {\n      // do something once the mutation succeeded\n    },\n    onFailure({ error, rollback, input }) {\n      // do something once the mutation failed\n    },\n    onSettled({ status, error, data, rollback, input }) {\n      switch (status) {\n        case 'success': {\n          // do something if the mutation succeeded\n        }\n        case 'failure': {\n          // do something if the mutation failed\n        }\n      }\n    },\n  });\n\n  const handleSubmit = React.useCallback(\n    function handleSubmit(event) {\n      mutate({ authorId, comment });\n    },\n    [mutate, comment]\n  );\n\n  // render your UI\n}\n```\n\n### Usage with SWR\n\nIf you are using SWR, you can use `useMutation` to run your mutations to perform Optimistic UI changes.\n\n```tsx\nimport { cache, mutate } from 'swr';\n\nfunction createComment(input) {\n  // ...\n}\n\nfunction useCreateComment() {\n  return useMutation(createComment, {\n    onMutate({ input }) {\n      const oldData = cache.get('comment-list');\n      // optimistically update the data before your mutation is run\n      mutate('comment-list', current =\u003e current.concat(input), false);\n      return () =\u003e mutate('comment-list', oldData, false); // rollback if it failed\n    },\n\n    onFailure({ rollback }) {\n      if (rollback) rollback();\n    },\n  });\n}\n```\n\nThis way when you run `mutate`, it will first optimistically update your SWR cache and if it fails it will rollback to the old data.\n\n## API Reference\n\n```tsx\nconst [mutate, { status, data, error, reset }] = useMutation\u003c\n  Input,\n  Data,\n  Error\n\u003e(mutationFn, {\n  onMutate,\n  onSuccess,\n  onFailure,\n  onSettled,\n  throwOnFailure,\n  useErrorBoundary,\n});\n\nconst promise = mutate(input, {\n  onSuccess,\n  onSettled,\n  onError,\n  throwOnFailure,\n});\n```\n\n### Hook Generic\n\n\u003e Only if you are using TypeScript\n\n- `Input = any`\n  - The data your mutation function needs to run\n- `Data = any`\n  - The data the hook will return as result of your mutation\n- `Error = any`\n  - The error the hook will return as a failure in your mutation\n\n### Hook Options\n\n- `mutationFn(input: Input): Promise\u003cData\u003e`\n  - **Required**\n  - A function to be executed before the mutation runs.\n  - It receives the same input as the mutate function.\n  - It can be an async or sync function, in both cases if it returns a function it will keep it as a way to rollback the changed applied inside onMutate.\n- `onMutate?({ input: Input }): Promise\u003crollbackFn | undefined\u003e | rollbackFn | undefined`\n  - Optional\n  - A function to be executed before the mutation runs.\n  - It receives the same input as the mutate function.\n  - It can be an async or sync function, in both cases if it returns a function.\n  - it will keep it as a way to rollback the changed applied inside `onMutate`\n- `onSuccess?({ data: Data, input: Input }): Promise\u003cvoid\u003e | void`\n  - Optional\n  - A function to be executed after the mutation resolves successfully.\n  - It receives the result of the mutation.\n  - If a Promise is returned, it will be awaited before proceeding.\n- `onFailure?({ error: Error, rollback: rollbackFn, input: Input }): Promise\u003cvoid\u003e | void`\n  - Optional\n  - A function to be executed after the mutation failed to execute.\n  - If a Promise is returned, it will be awaited before proceeding.\n- `onSettled?({ status: 'success' | 'failure', error?: Error, data?: Data, rollback?: rollbackFn, input: Input}): Promise\u003cvoid\u003e | void`\n  - Optional\n  - A function to be executed after the mutation has resolves, either successfully or as failure.\n  - This function receives the error or the result of the mutation.\n  - If a Promise is returned, it will be awaited before proceeding.\n- `throwOnFailure?: boolean`\n  - Optional\n  - If defined as `true`, a failure in the mutation will cause the `mutate` function to throw. Disabled by default.\n- `useErrorBoundary?: boolean` (default false)\n  - Optional\n  - If defined as `true`, a failure in the mutation will cause the Hook to throw in render time, making error boundaries catch the error.\n\n### Hook Returned Value\n\n- `mutate(input: Input, config: Omit\u003cOptions\u003cInput, Data, Error\u003e, 'onMutate' | 'useErrorBoundary'\u003e = {}): Promise\u003cData | undefined\u003e`\n  - The function you call to trigger your mutation, passing the input your mutation function needs.\n  - All the lifecycle callback defined here will run _after_ the callback defined in the Hook.\n- `status: 'idle' | 'running' | 'success' | 'failure'`\n  - The current status of the mutation, it will be:\n    - `idle` initial status of the hook, and the status after a reset\n    - `running` if the mutation is currently running\n    - `success` if the mutation resolved successfully\n    - `failure` if the mutation failed to resolve\n- `data: Data`\n  - The data returned as the result of the mutation.\n- `error: Error`\n  - The error returned as the result of the mutation.\n- `reset(): void\n  - A function to reset the internal state of the Hook to the orignal idle and clear any data or error.\n\n## Author\n\n- [Sergio Xalambrí](https://sergiodxa.com) - [Able](https://able.co)\n\n## License\n\nThe MIT License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsergiodxa%2Fuse-mutation","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsergiodxa%2Fuse-mutation","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsergiodxa%2Fuse-mutation/lists"}