Repository: tannerlinsley/react-query
Pull request #130 (2020-02-17 20:03:53)

reset error state when calling useMutation's `reset`
continuing off of https://github.com/tannerlinsley/react-query/pull/122, `reset` should also reset the error state as well.

- Resets `error` when calling `reset`
- Adds a test for the error case
- Updates the CHANGELOG and README for the `reset` API
- Also as promised, made a PR for TS types: https://github.com/DefinitelyTyped/DefinitelyTyped/pull/42431

size-plugin[bot]: 
Size report for the changes in this PR: 

  
sizes-cjs Overall size: 7.32 kB  (+5 B)

```
 index.js ⏤  7.32 kB (+5 B)

```
  

  
sizes-es Overall size: 7.18 kB  (+4 B)

```
 index.es.js ⏤  7.18 kB (+4 B)

```
  


commit: a0a7c445e84aa0bd3aba9dcf740ee0e1c878645c


#### like it?
⭐️ [me](https://github.com/kuldeepkeshwar/size-plugin-bot) 😊

  

Patch:
diff --git a/.size-snapshot.json b/.size-snapshot.json
index 991a8c0f9..89ac2495f 100644
--- a/.size-snapshot.json
+++ b/.size-snapshot.json
@@ -1,13 +1,13 @@
 {
   "dist/index.js": {
-    "bundled": 31764,
-    "minified": 16087,
-    "gzipped": 4618
+    "bundled": 31777,
+    "minified": 16088,
+    "gzipped": 4619
   },
   "dist/index.es.js": {
-    "bundled": 31223,
-    "minified": 15604,
-    "gzipped": 4516,
+    "bundled": 31236,
+    "minified": 15605,
+    "gzipped": 4517,
     "treeshaked": {
       "rollup": {
         "code": 3329,
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 801ba504f..0fd73a0ed 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,7 @@
 
 - Added the `useMutation.throwOnError` and corresponding `queryConfig.throwOnError` option to configure whether the `mutate` function rethrows errors encountered in the mutation function
 - Added the `useMutation.useErrorBoundary` and corresponding `queryConfig.useErrorBoundary` option to configure whether mutation errors should be thrown during the render function and propagated to the nearest error boundary. This option will default to the same value as `queryConfig.suspense` if not defined otherwise
+- Added a new `reset` function for `useMutation` which will revert the hook's state back to the initial `null` state
 
 ## 0.3.27
 
diff --git a/README.md b/README.md
index a694d7a9b..58020fdbf 100644
--- a/README.md
+++ b/README.md
@@ -947,6 +947,37 @@ mutate(
 const { data, isLoading, error } = useQuery(['todo', { id: 5 }], fetchTodoByID)
 ```
 
+### Resetting Mutation State
+
+It's sometimes the case that you need to clear the `error` or `data` of a mutation request. To do this, you can use the `reset` function to handle this:
+
+```js
+const CreateTodo = () => {
+  const [title, setTitle] = useState('')
+  const [mutate, { error, mutate }] = useMutation(createTodo)
+
+  const onCreateTodo = async e => {
+    e.preventDefault()
+    await mutate({ title })
+  }
+
+  return (
+    <form onSubmit={onCreateTodo}>
+      {error &&
+        <h5 onClick={() => reset()}>{error}</h5>
+      }
+      <input
+        type="text"
+        value={title}
+        onChange={e => setTitle(e.target.value)}
+      />
+      <br />
+      <button type="submit">Create Todo</button>
+    </form>
+  )
+}
+```
+
 ## Manually or Optimistically Setting Query Data
 
 In rare circumstances, you may want to manually update a query's response before it has been refetched. To do this, you can use the exported `setQueryData` function:
@@ -1385,7 +1416,7 @@ const {
 ## `useMutation`
 
 ```js
-const [mutate, { data, isLoading, error }] = useMutation(mutationFn, {
+const [mutate, { data, isLoading, error, reset }] = useMutation(mutationFn, {
   refetchQueries,
   refetchQueriesOnFailure,
   useErrorBoundary,
@@ -1433,6 +1464,8 @@ const promise = mutate(variables, { updateQuery, waitForRefetchQueries })
   - The last successfully resolved data for the query.
 - `error: null | Error`
   - The error object for the query, if an error was thrown.
+- `reset: Function() => void`
+  - Sets the mutation's `data` and `error` fields to `null`.
 - `isLoading: Boolean`
   - Will be `true` if the query is both fetching and does not have any cached data.
 - `promise: Promise`
diff --git a/src/index.js b/src/index.js
index d80107ad2..2f9ee66f1 100644
--- a/src/index.js
+++ b/src/index.js
@@ -697,7 +697,10 @@ export function useMutation(
     [refetchQueries, refetchQueriesOnFailure, throwOnError]
   )
 
-  const reset = React.useCallback(() => setData(null), [])
+  const reset = React.useCallback(() => {
+    setData(null)
+    setError(null)
+  }, [])
 
   React.useEffect(() => {
     if (useErrorBoundary && error) {


Test patch:
diff --git a/src/__tests__/useMutation-test.js b/src/__tests__/useMutation-test.js
index 07afa9d42..96e50d990 100644
--- a/src/__tests__/useMutation-test.js
+++ b/src/__tests__/useMutation-test.js
@@ -5,7 +5,6 @@ import {
   waitForElement,
 } from '@testing-library/react'
 import * as React from 'react'
-import { act } from 'react-dom/test-utils'
 
 import { useMutation } from '../index'
 
@@ -43,4 +42,39 @@ describe('useMutation', () => {
 
     expect(getByTestId('title').textContent).toBe('')
   })
+
+  it('should be able to reset `error`', async () => {
+    function Page() {
+      const [mutate, mutationResult] = useMutation(
+        () => Promise.reject(new Error('something went wrong')),
+        {
+          throwOnError: false
+        }
+      )
+
+      return (
+        <div>
+          {mutationResult.error &&
+            <h1 data-testid="error">{mutationResult.error.message}</h1>
+          }
+          <button onClick={mutationResult.reset}>reset</button>
+          <button onClick={mutate}>mutate</button>
+        </div>
+      )
+    }
+
+    const { getByTestId, getByText, queryByTestId } = render(<Page />)
+
+    expect(queryByTestId('error')).toBeNull()
+
+    fireEvent.click(getByText('mutate'))
+
+    await waitForElement(() => getByTestId('error'))
+
+    expect(getByTestId('error').textContent).toBe('something went wrong')
+
+    fireEvent.click(getByText('reset'))
+
+    expect(queryByTestId('error')).toBeNull()
+  })
 })