Skip to content

Commit 91db428

Browse files
committed
fix(core): make sure mutations get updated options
this fixes an issue around stale closures where callbacks are not updated, thus are called with wrong values in the closure
1 parent a81da97 commit 91db428

File tree

3 files changed

+44
-6
lines changed

3 files changed

+44
-6
lines changed

packages/query-core/src/mutation.ts

+12-6
Original file line numberDiff line numberDiff line change
@@ -89,31 +89,37 @@ export class Mutation<
8989
TContext = unknown,
9090
> extends Removable {
9191
state: MutationState<TData, TError, TVariables, TContext>
92-
options: MutationOptions<TData, TError, TVariables, TContext>
92+
options!: MutationOptions<TData, TError, TVariables, TContext>
9393
mutationId: number
9494

9595
private observers: MutationObserver<TData, TError, TVariables, TContext>[]
96+
private defaultOptions?: MutationOptions<TData, TError, TVariables, TContext>
9697
private mutationCache: MutationCache
9798
private logger: Logger
9899
private retryer?: Retryer<TData>
99100

100101
constructor(config: MutationConfig<TData, TError, TVariables, TContext>) {
101102
super()
102103

103-
this.options = {
104-
...config.defaultOptions,
105-
...config.options,
106-
}
104+
this.defaultOptions = config.defaultOptions
107105
this.mutationId = config.mutationId
108106
this.mutationCache = config.mutationCache
109107
this.logger = config.logger || defaultLogger
110108
this.observers = []
111109
this.state = config.state || getDefaultState()
112110

113-
this.updateCacheTime(this.options.cacheTime)
111+
this.setOptions(config.options)
114112
this.scheduleGc()
115113
}
116114

115+
setOptions(
116+
options?: MutationOptions<TData, TError, TVariables, TContext>,
117+
): void {
118+
this.options = { ...this.defaultOptions, ...options }
119+
120+
this.updateCacheTime(this.options.cacheTime)
121+
}
122+
117123
get meta(): MutationMeta | undefined {
118124
return this.options.meta
119125
}

packages/query-core/src/mutationObserver.ts

+1
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ export class MutationObserver<
7474
observer: this,
7575
})
7676
}
77+
this.currentMutation?.setOptions(this.options)
7778
}
7879

7980
protected onUnsubscribe(): void {

packages/query-core/src/tests/mutations.test.tsx

+31
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { QueryClient } from '..'
22
import { createQueryClient, executeMutation, queryKey, sleep } from './utils'
33
import type { MutationState } from '../mutation'
44
import { MutationObserver } from '../mutationObserver'
5+
import { waitFor } from '@testing-library/react'
56

67
describe('mutations', () => {
78
let queryClient: QueryClient
@@ -358,4 +359,34 @@ describe('mutations', () => {
358359
expect(onSuccess).not.toHaveBeenCalled()
359360
expect(onSettled).not.toHaveBeenCalled()
360361
})
362+
363+
test('mutation callbacks should see updated options', async () => {
364+
const onSuccess = jest.fn()
365+
366+
const mutation = new MutationObserver(queryClient, {
367+
mutationFn: async () => {
368+
sleep(100)
369+
return 'update'
370+
},
371+
onSuccess: () => {
372+
onSuccess(1)
373+
},
374+
})
375+
376+
void mutation.mutate()
377+
378+
mutation.setOptions({
379+
mutationFn: async () => {
380+
sleep(100)
381+
return 'update'
382+
},
383+
onSuccess: () => {
384+
onSuccess(2)
385+
},
386+
})
387+
388+
await waitFor(() => expect(onSuccess).toHaveBeenCalledTimes(1))
389+
390+
expect(onSuccess).toHaveBeenCalledWith(2)
391+
})
361392
})

0 commit comments

Comments
 (0)