Skip to content

Commit ce4474b

Browse files
committed
feat: resetQueries refetches active queries
1 parent 9883c41 commit ce4474b

File tree

5 files changed

+174
-7
lines changed

5 files changed

+174
-7
lines changed

docs/src/pages/reference/QueryClient.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ property/state of the query.
284284
This will notify subscribers — unlike `clear`, which removes all
285285
subscribers — and reset the query to its pre-loaded state — unlike
286286
`invalidateQueries`. If a query has `initialData`, the query's data will be
287-
reset to that.
287+
reset to that. If a query is active, it will be refetched.
288288

289289
```js
290290
queryClient.resetQueries(queryKey, { exact: true })
@@ -294,10 +294,13 @@ queryClient.resetQueries(queryKey, { exact: true })
294294

295295
- `queryKey?: QueryKey`: [Query Keys](../guides/query-keys)
296296
- `filters?: QueryFilters`: [Query Filters](../guides/query-filters)
297+
- `resetOptions?: ResetOptions`:
298+
- `throwOnError?: boolean`
299+
- When set to `true`, this method will throw if any of the query refetch tasks fail.
297300

298301
**Returns**
299302

300-
This method does not return anything
303+
This method returns a promise that resolves when all active queries have been refetched.
301304

302305
## `queryClient.isFetching`
303306

src/core/queryClient.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import type {
2020
QueryObserverOptions,
2121
QueryOptions,
2222
RefetchOptions,
23+
ResetOptions,
2324
} from './types'
2425
import type { QueryState, SetDataOptions } from './query'
2526
import { QueryCache } from './queryCache'
@@ -132,15 +133,22 @@ export class QueryClient {
132133
})
133134
}
134135

135-
resetQueries(filters?: QueryFilters): void
136-
resetQueries(queryKey?: QueryKey, filters?: QueryFilters): void
137-
resetQueries(arg1?: QueryKey | QueryFilters, arg2?: QueryFilters): void {
138-
const [filters] = parseFilterArgs(arg1, arg2)
136+
resetQueries(filters?: QueryFilters, options?: ResetOptions): Promise<void>
137+
resetQueries(queryKey?: QueryKey, filters?: QueryFilters, options?: ResetOptions): Promise<void>
138+
resetQueries(arg1?: QueryKey | QueryFilters, arg2?: QueryFilters | ResetOptions, arg3?: ResetOptions): Promise<void> {
139+
const [filters, options] = parseFilterArgs(arg1, arg2, arg3)
139140
const queryCache = this.queryCache
140-
notifyManager.batch(() => {
141+
142+
const refetchFilters: QueryFilters = {
143+
...filters,
144+
active: true,
145+
}
146+
147+
return notifyManager.batch(() => {
141148
queryCache.findAll(filters).forEach(query => {
142149
query.reset()
143150
})
151+
return this.refetchQueries(refetchFilters, options)
144152
})
145153
}
146154

src/core/tests/queryCache.test.tsx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -998,6 +998,33 @@ describe('queryCache', () => {
998998
expect(state?.data).toEqual('initial')
999999
})
10001000

1001+
test('resetQueries should refetch all active queries', async () => {
1002+
const key1 = queryKey()
1003+
const key2 = queryKey()
1004+
const queryFn1 = jest.fn()
1005+
const queryFn2 = jest.fn()
1006+
const testCache = new QueryCache()
1007+
const testClient = new QueryClient({ queryCache: testCache })
1008+
const observer1 = new QueryObserver(testClient, {
1009+
queryKey: key1,
1010+
queryFn: queryFn1,
1011+
enabled: true,
1012+
})
1013+
const observer2 = new QueryObserver(testClient, {
1014+
queryKey: key2,
1015+
queryFn: queryFn2,
1016+
enabled: false,
1017+
})
1018+
observer1.subscribe()
1019+
observer2.subscribe()
1020+
await testClient.resetQueries()
1021+
observer2.destroy()
1022+
observer1.destroy()
1023+
testCache.clear()
1024+
expect(queryFn1).toHaveBeenCalledTimes(2)
1025+
expect(queryFn2).toHaveBeenCalledTimes(0)
1026+
})
1027+
10011028
test('find should filter correctly', async () => {
10021029
const key = queryKey()
10031030
const testCache = new QueryCache()

src/core/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,10 @@ export interface InvalidateOptions {
214214
throwOnError?: boolean
215215
}
216216

217+
export interface ResetOptions {
218+
throwOnError?: boolean
219+
}
220+
217221
export interface FetchNextPageOptions extends ResultOptions {
218222
pageParam?: unknown
219223
}

src/react/tests/useQuery.test.tsx

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2852,4 +2852,129 @@ describe('useQuery', () => {
28522852

28532853
expect(cancelFn).toHaveBeenCalled()
28542854
})
2855+
2856+
it('should update query state and refetch when reset with resetQueries', async () => {
2857+
const key = queryKey()
2858+
const states: UseQueryResult<number>[] = []
2859+
let count = 0
2860+
2861+
function Page() {
2862+
const state = useQuery(
2863+
key,
2864+
() => {
2865+
count++
2866+
return count
2867+
},
2868+
{ staleTime: Infinity }
2869+
)
2870+
2871+
states.push(state)
2872+
2873+
React.useEffect(() => {
2874+
setActTimeout(() => {
2875+
queryClient.resetQueries(key)
2876+
}, 10)
2877+
}, [])
2878+
2879+
return null
2880+
}
2881+
2882+
renderWithClient(queryClient, <Page />)
2883+
2884+
await sleep(100)
2885+
2886+
expect(states.length).toBe(4)
2887+
expect(states[0]).toMatchObject({
2888+
data: undefined,
2889+
isLoading: true,
2890+
isFetching: true,
2891+
isSuccess: false,
2892+
isStale: true,
2893+
})
2894+
expect(states[1]).toMatchObject({
2895+
data: 1,
2896+
isLoading: false,
2897+
isFetching: false,
2898+
isSuccess: true,
2899+
isStale: false,
2900+
})
2901+
expect(states[2]).toMatchObject({
2902+
data: undefined,
2903+
isLoading: true,
2904+
isFetching: true,
2905+
isSuccess: false,
2906+
isStale: true,
2907+
})
2908+
expect(states[3]).toMatchObject({
2909+
data: 2,
2910+
isLoading: false,
2911+
isFetching: false,
2912+
isSuccess: true,
2913+
isStale: false,
2914+
})
2915+
})
2916+
2917+
it('should update query state and not refetch when resetting a disabled query with resetQueries', async () => {
2918+
const key = queryKey()
2919+
const states: UseQueryResult<number>[] = []
2920+
let count = 0
2921+
2922+
function Page() {
2923+
const state = useQuery(
2924+
key,
2925+
() => {
2926+
count++
2927+
return count
2928+
},
2929+
{ staleTime: Infinity, enabled: false }
2930+
)
2931+
2932+
states.push(state)
2933+
2934+
React.useEffect(() => {
2935+
setActTimeout(() => {
2936+
state.refetch()
2937+
}, 0)
2938+
setActTimeout(() => {
2939+
queryClient.resetQueries(key)
2940+
}, 50)
2941+
}, [])
2942+
2943+
return null
2944+
}
2945+
2946+
renderWithClient(queryClient, <Page />)
2947+
2948+
await sleep(100)
2949+
2950+
expect(states.length).toBe(4)
2951+
expect(states[0]).toMatchObject({
2952+
data: undefined,
2953+
isLoading: false,
2954+
isFetching: false,
2955+
isSuccess: false,
2956+
isStale: true,
2957+
})
2958+
expect(states[1]).toMatchObject({
2959+
data: undefined,
2960+
isLoading: true,
2961+
isFetching: true,
2962+
isSuccess: false,
2963+
isStale: true,
2964+
})
2965+
expect(states[2]).toMatchObject({
2966+
data: 1,
2967+
isLoading: false,
2968+
isFetching: false,
2969+
isSuccess: true,
2970+
isStale: false,
2971+
})
2972+
expect(states[3]).toMatchObject({
2973+
data: undefined,
2974+
isLoading: false,
2975+
isFetching: false,
2976+
isSuccess: false,
2977+
isStale: true,
2978+
})
2979+
})
28552980
})

0 commit comments

Comments
 (0)