Skip to content

Commit 09116e5

Browse files
authored
feat(queryClient): add setQueriesData utility (TanStack#2204)
* feat(queryClient): add setQueriesData utility a function which can be used to fuzzily set queryData for multiple queries * feat(queryClient): add setQueriesData utility docs * feat(queryClient): add setQueriesData utility improve docs * feat(queryClient): add setQueriesData utility wrap setQueriesData in notifyManager.batch to avoid unnecessary re-renders
1 parent c8b3ff2 commit 09116e5

File tree

3 files changed

+83
-1
lines changed

3 files changed

+83
-1
lines changed

docs/src/pages/reference/QueryClient.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Its available methods are:
2929
- [`prefetchInfiniteQuery`](#queryclientprefetchinfinitequery)
3030
- [`getQueryData`](#queryclientgetquerydata)
3131
- [`setQueryData`](#queryclientsetquerydata)
32+
- [`setQueriesData`](#queryclientsetqueriesdata)
3233
- [`getQueryState`](#queryclientgetquerystate)
3334
- [`invalidateQueries`](#queryclientinvalidatequeries)
3435
- [`refetchQueries`](#queryclientrefetchqueries)
@@ -187,7 +188,7 @@ queryClient.setQueryData(queryKey, updater)
187188
**Options**
188189

189190
- `queryKey: QueryKey`: [Query Keys](../guides/query-keys)
190-
- `updater: unknown | (oldData: TData | undefined) => TData`
191+
- `updater: TData | (oldData: TData | undefined) => TData`
191192
- If non-function is passed, the data will be updated to this value
192193
- If a function is passed, it will receive the old data value and be expected to return a new one.
193194

@@ -219,6 +220,22 @@ console.log(state.dataUpdatedAt)
219220
- `queryKey?: QueryKey`: [Query Keys](../guides/query-keys)
220221
- `filters?: QueryFilters`: [Query Filters](../guides/filters#query-filters)
221222

223+
## `queryClient.setQueriesData`
224+
225+
`setQueriesData` is a synchronous function that can be used to immediately update cached data of multiple queries. Only queries that match the passed queryKey or queryFilter will be updated - no new cache entries will be created. Under the hood, [`setQueryData`](#queryclientsetquerydata) is called for each query.
226+
227+
```js
228+
queryClient.setQueriesData(queryKey | filters, updater)
229+
```
230+
231+
**Options**
232+
233+
- `queryKey: QueryKey`: [Query Keys](../guides/query-keys) | `filters: QueryFilters`: [Query Filters](../guides/filters#query-filters)
234+
- if a queryKey is passed as first argument, queryKeys fuzzily matching this param will be updated
235+
- if a filter is passed, queryKeys matching the filter will be updated
236+
- `updater: TData | (oldData: TData | undefined) => TData`
237+
- the [setQueryData](#queryclientsetquerydata) updater function or new data, will be called for each matching queryKey
238+
222239
## `queryClient.invalidateQueries`
223240

224241
The `invalidateQueries` method can be used to invalidate and refetch single or multiple queries in the cache based on their query keys or any other functionally accessible property/state of the query. By default, all matching queries are immediately marked as invalid and active queries are refetched in the background.

src/core/queryClient.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,33 @@ export class QueryClient {
123123
.setData(updater, options)
124124
}
125125

126+
setQueriesData<TData>(
127+
queryKey: QueryKey,
128+
updater: Updater<TData | undefined, TData>,
129+
options?: SetDataOptions
130+
): [QueryKey, TData][]
131+
132+
setQueriesData<TData>(
133+
filters: QueryFilters,
134+
updater: Updater<TData | undefined, TData>,
135+
options?: SetDataOptions
136+
): [QueryKey, TData][]
137+
138+
setQueriesData<TData>(
139+
queryKeyOrFilters: QueryKey | QueryFilters,
140+
updater: Updater<TData | undefined, TData>,
141+
options?: SetDataOptions
142+
): [QueryKey, TData][] {
143+
return notifyManager.batch(() =>
144+
this.getQueryCache()
145+
.findAll(queryKeyOrFilters)
146+
.map(({ queryKey }) => [
147+
queryKey,
148+
this.setQueryData<TData>(queryKey, updater, options),
149+
])
150+
)
151+
}
152+
126153
getQueryState<TData = unknown, TError = undefined>(
127154
queryKey: QueryKey,
128155
filters?: QueryFilters

src/core/tests/queryClient.test.tsx

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,44 @@ describe('queryClient', () => {
166166
})
167167
})
168168

169+
describe('setQueriesData', () => {
170+
test('should update all existing, matching queries', () => {
171+
queryClient.setQueryData(['key', 1], 1)
172+
queryClient.setQueryData(['key', 2], 2)
173+
174+
const result = queryClient.setQueriesData<number>('key', old => old! + 5)
175+
176+
expect(result).toEqual([
177+
[['key', 1], 6],
178+
[['key', 2], 7],
179+
])
180+
expect(queryClient.getQueryData(['key', 1])).toBe(6)
181+
expect(queryClient.getQueryData(['key', 2])).toBe(7)
182+
})
183+
184+
test('should accept queryFilters', () => {
185+
queryClient.setQueryData(['key', 1], 1)
186+
queryClient.setQueryData(['key', 2], 2)
187+
const query1 = queryCache.find(['key', 1])!
188+
189+
const result = queryClient.setQueriesData<number>(
190+
{ predicate: query => query === query1 },
191+
old => old! + 5
192+
)
193+
194+
expect(result).toEqual([[['key', 1], 6]])
195+
expect(queryClient.getQueryData(['key', 1])).toBe(6)
196+
expect(queryClient.getQueryData(['key', 2])).toBe(2)
197+
})
198+
199+
test('should not update non existing queries', () => {
200+
const result = queryClient.setQueriesData<string>('key', 'data')
201+
202+
expect(result).toEqual([])
203+
expect(queryClient.getQueryData('key')).toBe(undefined)
204+
})
205+
})
206+
169207
describe('getQueryData', () => {
170208
test('should return the query data if the query is found', () => {
171209
const key = queryKey()

0 commit comments

Comments
 (0)