diff --git a/src/core/infiniteQueryBehavior.ts b/src/core/infiniteQueryBehavior.ts index 3fe93a0377..df8f8f9798 100644 --- a/src/core/infiniteQueryBehavior.ts +++ b/src/core/infiniteQueryBehavior.ts @@ -6,7 +6,6 @@ import type { QueryOptions, RefetchQueryFilters, } from './types' -import { getAbortController } from './utils' export function infiniteQueryBehavior< TQueryFnData, @@ -24,11 +23,25 @@ export function infiniteQueryBehavior< const isFetchingPreviousPage = fetchMore?.direction === 'backward' const oldPages = context.state.data?.pages || [] const oldPageParams = context.state.data?.pageParams || [] - const abortController = getAbortController() - const abortSignal = abortController?.signal let newPageParams = oldPageParams let cancelled = false + const addSignalProperty = (object: unknown) => { + Object.defineProperty(object, 'signal', { + enumerable: true, + get: () => { + if (context.signal?.aborted) { + cancelled = true + } else { + context.signal?.addEventListener('abort', () => { + cancelled = true + }) + } + return context.signal + }, + }) + } + // Get query function const queryFn = context.options.queryFn || (() => Promise.reject('Missing queryFn')) @@ -62,11 +75,12 @@ export function infiniteQueryBehavior< const queryFnContext: QueryFunctionContext = { queryKey: context.queryKey, - signal: abortSignal, pageParam: param, meta: context.meta, } + addSignalProperty(queryFnContext) + const queryFnResult = queryFn(queryFnContext) const promise = Promise.resolve(queryFnResult).then(page => @@ -143,11 +157,6 @@ export function infiniteQueryBehavior< pageParams: newPageParams, })) - context.signal?.addEventListener('abort', () => { - cancelled = true - abortController?.abort() - }) - return finalPromise } }, diff --git a/src/reactjs/tests/useInfiniteQuery.test.tsx b/src/reactjs/tests/useInfiniteQuery.test.tsx index 6253707e4b..21d24958a2 100644 --- a/src/reactjs/tests/useInfiniteQuery.test.tsx +++ b/src/reactjs/tests/useInfiniteQuery.test.tsx @@ -1033,29 +1033,28 @@ describe('useInfiniteQuery', () => { }) }) - it('should stop fetching additional pages when the component is unmounted', async () => { + it('should stop fetching additional pages when the component is unmounted and AbortSignal is consumed', async () => { const key = queryKey() - const states: UseInfiniteQueryResult[] = [] let fetches = 0 - const initialData = { pages: [1, 2, 3, 4], pageParams: [1, 2, 3, 4] } + const initialData = { pages: [1, 2, 3, 4], pageParams: [0, 1, 2, 3] } function List() { - const state = useInfiniteQuery( + useInfiniteQuery( key, - async ({ pageParam }) => { + async ({ pageParam = 0, signal: _ }) => { fetches++ await sleep(50) - return Number(pageParam) + return Number(pageParam) * 10 }, { initialData, - getNextPageParam: lastPage => lastPage + 1, + getNextPageParam: (_, allPages) => { + return allPages.length === 4 ? undefined : allPages.length + }, } ) - states.push(state) - return null } @@ -1075,13 +1074,22 @@ describe('useInfiniteQuery', () => { await sleep(300) - expect(states.length).toBe(1) - expect(fetches).toBe(2) - expect(queryClient.getQueryState(key)).toMatchObject({ - data: initialData, - status: 'success', - error: null, - }) + if (typeof AbortSignal === 'function') { + expect(fetches).toBe(2) + expect(queryClient.getQueryState(key)).toMatchObject({ + data: initialData, + status: 'success', + error: null, + }) + } else { + // if AbortSignal is not consumed, fetches should not abort + expect(fetches).toBe(4) + expect(queryClient.getQueryState(key)).toMatchObject({ + data: { pages: [0, 10, 20, 30], pageParams: [0, 1, 2, 3] }, + status: 'success', + error: null, + }) + } }) it('should be able to override the cursor in the fetchNextPage callback', async () => {