Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions .size-snapshot.json
Original file line number Diff line number Diff line change
@@ -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,
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While I believe this got merged as v0.3.26 in 3a8bda8, this would be more of a feature in semver terms. Let me know if you want me to move this to the v0.3.26 section


## 0.3.27

Expand Down
35 changes: 34 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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`
Expand Down
36 changes: 35 additions & 1 deletion src/__tests__/useMutation-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'

Expand Down Expand Up @@ -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()
})
})
5 changes: 4 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down