Skip to content

Commit 4806dfa

Browse files
authored
fix(query-core): have revertState capture manual updates (#9558)
1 parent 9ae770b commit 4806dfa

File tree

2 files changed

+50
-5
lines changed

2 files changed

+50
-5
lines changed

packages/query-core/src/__tests__/streamedQuery.test.tsx

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,47 @@ describe('streamedQuery', () => {
350350
unsubscribe()
351351
})
352352

353+
test('should abort when unsubscribed', async () => {
354+
const key = queryKey()
355+
const observer = new QueryObserver(queryClient, {
356+
queryKey: key,
357+
queryFn: streamedQuery({
358+
queryFn: (context) => {
359+
// just consume the signal
360+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
361+
const numbers = context.signal ? 3 : 0
362+
return createAsyncNumberGenerator(numbers)
363+
},
364+
}),
365+
})
366+
367+
const unsubscribe = observer.subscribe(vi.fn())
368+
369+
expect(queryClient.getQueryState(key)).toMatchObject({
370+
status: 'pending',
371+
fetchStatus: 'fetching',
372+
data: undefined,
373+
})
374+
375+
await vi.advanceTimersByTimeAsync(60)
376+
377+
expect(queryClient.getQueryState(key)).toMatchObject({
378+
status: 'success',
379+
fetchStatus: 'fetching',
380+
data: [0],
381+
})
382+
383+
unsubscribe()
384+
385+
await vi.advanceTimersByTimeAsync(10)
386+
387+
expect(queryClient.getQueryState(key)).toMatchObject({
388+
status: 'success',
389+
fetchStatus: 'idle',
390+
data: [0],
391+
})
392+
})
393+
353394
test('should support maxChunks', async () => {
354395
const key = queryKey()
355396
const observer = new QueryObserver(queryClient, {

packages/query-core/src/query.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -604,22 +604,26 @@ export class Query<
604604
fetchMeta: action.meta ?? null,
605605
}
606606
case 'success':
607-
// If fetching ends successfully, we don't need revertState as a fallback anymore.
608-
this.#revertState = undefined
609-
return {
607+
const newState = {
610608
...state,
611609
data: action.data,
612610
dataUpdateCount: state.dataUpdateCount + 1,
613611
dataUpdatedAt: action.dataUpdatedAt ?? Date.now(),
614612
error: null,
615613
isInvalidated: false,
616-
status: 'success',
614+
status: 'success' as const,
617615
...(!action.manual && {
618-
fetchStatus: 'idle',
616+
fetchStatus: 'idle' as const,
619617
fetchFailureCount: 0,
620618
fetchFailureReason: null,
621619
}),
622620
}
621+
622+
// If fetching ends successfully, we don't need revertState as a fallback anymore.
623+
// For manual updates, capture the state to revert to it in case of a cancellation.
624+
this.#revertState = action.manual ? newState : undefined
625+
626+
return newState
623627
case 'error':
624628
const error = action.error
625629

0 commit comments

Comments
 (0)