Skip to content

Commit 37c27ef

Browse files
authored
Merge pull request #3547 from reduxjs/select-cached-args
2 parents a148ad1 + 130ee8d commit 37c27ef

File tree

5 files changed

+122
-15
lines changed

5 files changed

+122
-15
lines changed

docs/rtk-query/api/created-api/api-slice-utils.mdx

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -268,14 +268,12 @@ It returns an array that contains
268268
#### Example
269269

270270
```ts no-transpile
271-
dispatch(api.util.selectInvalidatedBy(state, ['Post']))
272-
dispatch(api.util.selectInvalidatedBy(state, [{ type: 'Post', id: 1 }]))
273-
dispatch(
274-
api.util.selectInvalidatedBy(state, [
275-
{ type: 'Post', id: 1 },
276-
{ type: 'Post', id: 4 },
277-
])
278-
)
271+
const entries = api.util.selectInvalidatedBy(state, ['Post'])
272+
const entries = api.util.selectInvalidatedBy(state, [{ type: 'Post', id: 1 }])
273+
const entries = api.util.selectInvalidatedBy(state, [
274+
{ type: 'Post', id: 1 },
275+
{ type: 'Post', id: 4 },
276+
])
279277
```
280278

281279
### `invalidateTags`
@@ -318,6 +316,39 @@ dispatch(
318316
)
319317
```
320318

319+
### `selectCachedArgsForQuery`
320+
321+
#### Signature
322+
323+
```ts no-transpile
324+
function selectCachedArgsForQuery(
325+
state: RootState,
326+
queryName: QueryName
327+
): Array<QueryArg>
328+
```
329+
330+
- **Parameters**
331+
- `state`: the root state
332+
- `queryName`: a string matching an existing query endpoint name
333+
334+
#### Description
335+
336+
A function that can select arguments for currently cached queries.
337+
338+
The function accepts two arguments
339+
340+
- the root state and
341+
342+
- the name of the query
343+
344+
It returns an array that contains arguments used for each entry.
345+
346+
#### Example
347+
348+
```ts no-transpile
349+
const args = api.util.selectCachedArgsForQuery(state, 'getPosts')
350+
```
351+
321352
### `resetApiState`
322353

323354
#### Signature

docs/rtk-query/api/created-api/overview.mdx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ type Api = {
6161
originalArgs: any
6262
queryCacheKey: string
6363
}>
64+
selectCachedArgsForQuery: (
65+
state: FullState,
66+
endpointName: EndpointName
67+
) => Array<QueryArg>
6468
resetApiState: ActionCreator<ResetAction>
6569
getRunningQueryThunk(
6670
endpointName: EndpointName,

packages/toolkit/src/query/core/buildSelectors.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import type {
55
RootState as _RootState,
66
RequestStatusFlags,
77
QueryCacheKey,
8+
QueryKeys,
9+
QueryState,
810
} from './apiState'
911
import { QueryStatus, getRequestStatusFlags } from './apiState'
1012
import type {
@@ -130,7 +132,12 @@ export function buildSelectors<
130132
const selectSkippedQuery = (state: RootState) => defaultQuerySubState
131133
const selectSkippedMutation = (state: RootState) => defaultMutationSubState
132134

133-
return { buildQuerySelector, buildMutationSelector, selectInvalidatedBy }
135+
return {
136+
buildQuerySelector,
137+
buildMutationSelector,
138+
selectInvalidatedBy,
139+
selectCachedArgsForQuery,
140+
}
134141

135142
function withRequestFlags<T extends { status: QueryStatus }>(
136143
substate: T
@@ -238,4 +245,22 @@ export function buildSelectors<
238245
})
239246
)
240247
}
248+
249+
function selectCachedArgsForQuery<QueryName extends QueryKeys<Definitions>>(
250+
state: RootState,
251+
queryName: QueryName
252+
): Array<QueryArgFrom<Definitions[QueryName]>> {
253+
return Object.values(state[reducerPath].queries as QueryState<any>)
254+
.filter(
255+
(
256+
entry
257+
): entry is Exclude<
258+
QuerySubState<Definitions[QueryName]>,
259+
{ status: QueryStatus.uninitialized }
260+
> =>
261+
entry?.endpointName === queryName &&
262+
entry.status !== QueryStatus.uninitialized
263+
)
264+
.map((entry) => entry.originalArgs)
265+
}
241266
}

packages/toolkit/src/query/core/module.ts

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,16 @@ declare module '../apiTypes' {
356356
originalArgs: any
357357
queryCacheKey: string
358358
}>
359+
360+
/**
361+
* A function to select all arguments currently cached for a given endpoint.
362+
*
363+
* Can be used for mutations that want to do optimistic updates instead of invalidating a set of tags, but don't know exactly what they need to update.
364+
*/
365+
selectCachedArgsForQuery: <QueryName extends QueryKeys<Definitions>>(
366+
state: RootState<Definitions, string, ReducerPath>,
367+
queryName: QueryName
368+
) => Array<QueryArgFrom<Definitions[QueryName]>>
359369
}
360370
/**
361371
* Endpoints based on the input endpoints provided to `createApi`, containing `select` and `action matchers`.
@@ -527,13 +537,17 @@ export const coreModule = (): Module<CoreModule> => ({
527537

528538
safeAssign(api, { reducer: reducer as any, middleware })
529539

530-
const { buildQuerySelector, buildMutationSelector, selectInvalidatedBy } =
531-
buildSelectors({
532-
serializeQueryArgs: serializeQueryArgs as any,
533-
reducerPath,
534-
})
540+
const {
541+
buildQuerySelector,
542+
buildMutationSelector,
543+
selectInvalidatedBy,
544+
selectCachedArgsForQuery,
545+
} = buildSelectors({
546+
serializeQueryArgs: serializeQueryArgs as any,
547+
reducerPath,
548+
})
535549

536-
safeAssign(api.util, { selectInvalidatedBy })
550+
safeAssign(api.util, { selectInvalidatedBy, selectCachedArgsForQuery })
537551

538552
const {
539553
buildInitiateQuery,

packages/toolkit/src/query/tests/buildSelector.test.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,37 @@ describe('buildSelector', () => {
5252
const upperTitle = todoTitle.toUpperCase()
5353
expectExactType<string>(upperTitle)
5454
})
55+
test.skip('selectCachedArgsForQuery typetest', () => {
56+
interface Todo {
57+
userId: number
58+
id: number
59+
title: string
60+
completed: boolean
61+
}
62+
63+
type Todos = Array<Todo>
64+
65+
const exampleApi = createApi({
66+
reducerPath: 'api',
67+
baseQuery: fetchBaseQuery({
68+
baseUrl: 'https://jsonplaceholder.typicode.com',
69+
}),
70+
endpoints: (build) => ({
71+
getTodos: build.query<Todos, string>({
72+
query: () => '/todos',
73+
}),
74+
}),
75+
})
76+
77+
const store = configureStore({
78+
reducer: {
79+
[exampleApi.reducerPath]: exampleApi.reducer,
80+
other: () => 1,
81+
},
82+
})
83+
84+
expectExactType<string[]>(
85+
exampleApi.util.selectCachedArgsForQuery(store.getState(), 'getTodos')
86+
)
87+
})
5588
})

0 commit comments

Comments
 (0)