Skip to content

Commit

Permalink
fix(useIsFetching): account for fetches happening in the same render …
Browse files Browse the repository at this point in the history
…cycle (#3438)

if a fetch happens in the same render cycle as useIsFetching is mounting, but it is mounted after the query, what happens is that:

- the initial state of `isFetching` is `0` because the effect to fetch the query hasn't started yet
- the query effect runs before the isFetching effect, which means we miss the event, thus the next event we get from the subscription gives us 0 again

so we need to check for isFetching in the effect that runs to set up the subscription as well. This catches fetches that basically started in the same effect cycle, but before "our" effect ran
  • Loading branch information
TkDodo authored Mar 24, 2022
1 parent ce61a2a commit 31bcaf1
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 5 deletions.
27 changes: 26 additions & 1 deletion src/react/tests/useIsFetching.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ describe('useIsFetching', () => {
}

renderWithClient(queryClient, <Page />)
await waitFor(() => expect(isFetchings).toEqual([0, 0, 1, 2, 1, 0]))
await waitFor(() => expect(isFetchings).toEqual([0, 1, 1, 2, 1, 0]))
expect(consoleMock).not.toHaveBeenCalled()
expect(consoleMock.mock.calls[0]?.[0] ?? '').not.toMatch('setState')

Expand Down Expand Up @@ -159,4 +159,29 @@ describe('useIsFetching', () => {
await sleep(100)
expect(isFetchings).toEqual([0, 0, 1, 0])
})

it('should show the correct fetching state when mounted after a query', async () => {
const queryClient = new QueryClient()
const key = queryKey()

function Page() {
useQuery(key, async () => {
await sleep(10)
return 'test'
})

const isFetching = useIsFetching()

return (
<div>
<div>isFetching: {isFetching}</div>
</div>
)
}

const rendered = renderWithClient(queryClient, <Page />)

await rendered.findByText('isFetching: 1')
await rendered.findByText('isFetching: 0')
})
})
30 changes: 26 additions & 4 deletions src/react/useIsFetching.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,21 @@ import React from 'react'
import { notifyManager } from '../core/notifyManager'
import { QueryKey } from '../core/types'
import { parseFilterArgs, QueryFilters } from '../core/utils'
import { QueryClient } from '../core'
import { useQueryClient } from './QueryClientProvider'

const checkIsFetching = (
queryClient: QueryClient,
filters: QueryFilters,
isFetching: number,
setIsFetching: React.Dispatch<React.SetStateAction<number>>
) => {
const newIsFetching = queryClient.isFetching(filters)
if (isFetching !== newIsFetching) {
setIsFetching(newIsFetching)
}
}

export function useIsFetching(filters?: QueryFilters): number
export function useIsFetching(
queryKey?: QueryKey,
Expand All @@ -31,13 +44,22 @@ export function useIsFetching(
React.useEffect(() => {
mountedRef.current = true

checkIsFetching(
queryClient,
filtersRef.current,
isFetchingRef.current,
setIsFetching
)

const unsubscribe = queryClient.getQueryCache().subscribe(
notifyManager.batchCalls(() => {
if (mountedRef.current) {
const newIsFetching = queryClient.isFetching(filtersRef.current)
if (isFetchingRef.current !== newIsFetching) {
setIsFetching(newIsFetching)
}
checkIsFetching(
queryClient,
filtersRef.current,
isFetchingRef.current,
setIsFetching
)
}
})
)
Expand Down

1 comment on commit 31bcaf1

@vercel
Copy link

@vercel vercel bot commented on 31bcaf1 Mar 24, 2022

Choose a reason for hiding this comment

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

Please sign in to comment.