Skip to content

Commit

Permalink
fix: queries should not end up in an error state when a component unm…
Browse files Browse the repository at this point in the history
…ounts (TanStack#1781)
  • Loading branch information
boschni authored Feb 12, 2021
1 parent 4a821b0 commit f9f9cce
Show file tree
Hide file tree
Showing 4 changed files with 17 additions and 34 deletions.
26 changes: 7 additions & 19 deletions src/core/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ export class Query<
queryHash: string
options!: QueryOptions<TQueryFnData, TError, TData>
initialState: QueryState<TData, TError>
revertState?: QueryState<TData, TError>
state: QueryState<TData, TError>
cacheTime!: number

Expand Down Expand Up @@ -301,7 +302,7 @@ export class Query<
// we'll let the query continue so the result can be cached
if (this.retryer) {
if (this.retryer.isTransportCancelable) {
this.retryer.cancel()
this.retryer.cancel({ revert: true })
} else {
this.retryer.cancelRetry()
}
Expand Down Expand Up @@ -378,6 +379,9 @@ export class Query<
this.options.behavior?.onFetch(context)
}

// Store state in case the current fetch needs to be reverted
this.revertState = this.state

// Set to fetching state if not already in it
if (
!this.state.isFetching ||
Expand Down Expand Up @@ -530,24 +534,8 @@ export class Query<
case 'error':
const error = action.error as unknown

if (isCancelledError(error) && error.revert) {
let previousStatus: QueryStatus

if (!state.dataUpdatedAt && !state.errorUpdatedAt) {
previousStatus = 'idle'
} else if (state.dataUpdatedAt > state.errorUpdatedAt) {
previousStatus = 'success'
} else {
previousStatus = 'error'
}

return {
...state,
fetchFailureCount: 0,
isFetching: false,
isPaused: false,
status: previousStatus,
}
if (isCancelledError(error) && error.revert && this.revertState) {
return { ...this.revertState }
}

return {
Expand Down
3 changes: 1 addition & 2 deletions src/core/tests/query.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,7 @@ describe('query', () => {
expect(cancel).toHaveBeenCalled()
expect(query.state).toMatchObject({
data: undefined,
status: 'error',
errorUpdateCount: 1,
status: 'idle',
})
})

Expand Down
10 changes: 6 additions & 4 deletions src/react/tests/useInfiniteQuery.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import {
QueryClient,
QueryCache,
} from '../..'
import { CancelledError } from '../../core'

interface Result {
items: number[]
Expand Down Expand Up @@ -726,6 +725,8 @@ describe('useInfiniteQuery', () => {
const states: UseInfiniteQueryResult<number>[] = []
let fetches = 0

const initialData = { pages: [1, 2, 3, 4], pageParams: [1, 2, 3, 4] }

function List() {
const state = useInfiniteQuery(
key,
Expand All @@ -735,7 +736,7 @@ describe('useInfiniteQuery', () => {
return Number(pageParam)
},
{
initialData: { pages: [1, 2, 3, 4], pageParams: [1, 2, 3, 4] },
initialData,
getNextPageParam: lastPage => lastPage + 1,
}
)
Expand Down Expand Up @@ -764,8 +765,9 @@ describe('useInfiniteQuery', () => {
expect(states.length).toBe(1)
expect(fetches).toBe(2)
expect(queryClient.getQueryState(key)).toMatchObject({
status: 'error',
error: expect.any(CancelledError),
data: initialData,
status: 'success',
error: null,
})
})

Expand Down
12 changes: 3 additions & 9 deletions src/react/tests/useQuery.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
} from './utils'
import {
useQuery,
CancelledError,
QueryClient,
UseQueryResult,
QueryCache,
Expand Down Expand Up @@ -3421,7 +3420,7 @@ describe('useQuery', () => {
renderWithClient(queryClient, <Page />)

await sleep(100)
expect(states.length).toBe(5)
expect(states.length).toBe(4)
// Load query 1
expect(states[0]).toMatchObject({
status: 'loading',
Expand All @@ -3435,15 +3434,10 @@ describe('useQuery', () => {
// Load query 1
expect(states[2]).toMatchObject({
status: 'loading',
error: expect.any(CancelledError),
})
// State update
expect(states[3]).toMatchObject({
status: 'loading',
error: expect.any(CancelledError),
error: null,
})
// Loaded query 1
expect(states[4]).toMatchObject({
expect(states[3]).toMatchObject({
status: 'success',
error: null,
})
Expand Down

0 comments on commit f9f9cce

Please sign in to comment.