You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/framework/react/guides/mutations.md
+230-1Lines changed: 230 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -182,4 +182,233 @@ useMutation({
182
182
183
183
[//]: #'Example5'
184
184
185
-
You might find that you want to **trigger additional callbacks** beyond the ones defined on `useMutation` when calling `mutate`. This can be used to trigger component-specific side effects. To do that, you can provide any of the same callback options to the `
185
+
You might find that you want to **trigger additional callbacks** beyond the ones defined on `useMutation` when calling `mutate`. This can be used to trigger component-specific side effects. To do that, you can provide any of the same callback options to the `mutate` function after your mutation variable. Supported options include: `onSuccess`, `onError` and `onSettled`. Please keep in mind that those additional callbacks won't run if your component unmounts _before_ the mutation finishes.Add commentMore actions
186
+
187
+
[//]: #'Example6'
188
+
189
+
```tsx
190
+
useMutation({
191
+
mutationFn: addTodo,
192
+
onSuccess: (data, variables, context) => {
193
+
// I will fire first
194
+
},
195
+
onError: (error, variables, context) => {
196
+
// I will fire first
197
+
},
198
+
onSettled: (data, error, variables, context) => {
199
+
// I will fire first
200
+
},
201
+
})
202
+
203
+
mutate(todo, {
204
+
onSuccess: (data, variables, context) => {
205
+
// I will fire second!
206
+
},
207
+
onError: (error, variables, context) => {
208
+
// I will fire second!
209
+
},
210
+
onSettled: (data, error, variables, context) => {
211
+
// I will fire second!
212
+
},
213
+
})
214
+
```
215
+
216
+
[//]: #'Example6'
217
+
218
+
### Consecutive mutations
219
+
220
+
There is a slight difference in handling `onSuccess`, `onError` and `onSettled` callbacks when it comes to consecutive mutations. When passed to the `mutate` function, they will be fired up only _once_ and only if the component is still mounted. This is due to the fact that mutation observer is removed and resubscribed every time when the `mutate` function is called. On the contrary, `useMutation` handlers execute for each `mutate` call.
221
+
222
+
> Be aware that most likely, `mutationFn` passed to `useMutation` is asynchronous. In that case, the order in which mutations are fulfilled may differ from the order of `mutate` function calls.
223
+
224
+
[//]: #'Example7'
225
+
226
+
```tsx
227
+
useMutation({
228
+
mutationFn: addTodo,
229
+
onSuccess: (data, variables, context) => {
230
+
// Will be called 3 times
231
+
},
232
+
})
233
+
234
+
const todos = ['Todo 1', 'Todo 2', 'Todo 3']
235
+
todos.forEach((todo) => {
236
+
mutate(todo, {
237
+
onSuccess: (data, variables, context) => {
238
+
// Will execute only once, for the last mutation (Todo 3),
239
+
// regardless which mutation resolves first
240
+
},
241
+
})
242
+
})
243
+
```
244
+
245
+
[//]: #'Example7'
246
+
247
+
## Promises
248
+
249
+
Use `mutateAsync` instead of `mutate` to get a promise which will resolve on success or throw on an error. This can for example be used to compose side effects.
// If the mutation has been paused because the device is for example offline,
332
+
// Then the paused mutation can be dehydrated when the application quits:
333
+
const state =dehydrate(queryClient)
334
+
335
+
// The mutation can then be hydrated again when the application is started:
336
+
hydrate(queryClient, state)
337
+
338
+
// Resume the paused mutations:
339
+
queryClient.resumePausedMutations()
340
+
```
341
+
342
+
[//]: #'Example10'
343
+
344
+
### Persisting Offline mutations
345
+
346
+
If you persist offline mutations with the [persistQueryClient plugin](../plugins/persistQueryClient.md), mutations cannot be resumed when the page is reloaded unless you provide a default mutation function.
347
+
348
+
This is a technical limitation. When persisting to an external storage, only the state of mutations is persisted, as functions cannot be serialized. After hydration, the component that triggers the mutation might not be mounted, so calling `resumePausedMutations` might yield an error: `No mutationFn found`.
349
+
350
+
[//]: #'Example11'
351
+
352
+
```tsx
353
+
const persister =createSyncStoragePersister({
354
+
storage: window.localStorage,
355
+
})
356
+
const queryClient =newQueryClient({
357
+
defaultOptions: {
358
+
queries: {
359
+
gcTime: 1000*60*60*24, // 24 hours
360
+
},
361
+
},
362
+
})
363
+
364
+
// we need a default mutation function so that paused mutations can resume after a page reload
365
+
queryClient.setMutationDefaults(['todos'], {
366
+
mutationFn: ({ id, data }) => {
367
+
returnapi.updateTodo(id, data)
368
+
},
369
+
})
370
+
371
+
exportdefaultfunction App() {
372
+
return (
373
+
<PersistQueryClientProvider
374
+
client={queryClient}
375
+
persistOptions={{ persister }}
376
+
onSuccess={() => {
377
+
// resume mutations after initial restore from localStorage was successful
378
+
queryClient.resumePausedMutations()
379
+
}}
380
+
>
381
+
<RestOfTheApp />
382
+
</PersistQueryClientProvider>
383
+
)
384
+
}
385
+
```
386
+
387
+
[//]: #'Example11'
388
+
389
+
We also have an extensive [offline example](../examples/offline) that covers both queries and mutations.
390
+
391
+
## Mutation Scopes
392
+
393
+
Per default, all mutations run in parallel - even if you invoke `.mutate()` of the same mutation multiple times. Mutations can be given a `scope` with an `id` to avoid that. All mutations with the same `scope.id` will run in serial, which means when they are triggered, they will start in `isPaused: true` state if there is already a mutation for that scope in progress. They will be put into a queue and will automatically resume once their time in the queue has come.
394
+
395
+
[//]: #'ExampleScopes'
396
+
397
+
```tsx
398
+
const mutation =useMutation({
399
+
mutationFn: addTodo,
400
+
scope: {
401
+
id: 'todo',
402
+
},
403
+
})
404
+
```
405
+
406
+
[//]: #'ExampleScopes'
407
+
[//]: #'Materials'
408
+
409
+
## Further reading
410
+
411
+
For more information about mutations, have a look at [#12: Mastering Mutations in React Query](../community/tkdodos-blog.md#12-mastering-mutations-in-react-query) from
0 commit comments