Skip to content

Commit

Permalink
Merge pull request #3547 from reduxjs/select-cached-args
Browse files Browse the repository at this point in the history
  • Loading branch information
markerikson authored Sep 24, 2023
2 parents a148ad1 + 130ee8d commit 37c27ef
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 15 deletions.
47 changes: 39 additions & 8 deletions docs/rtk-query/api/created-api/api-slice-utils.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -268,14 +268,12 @@ It returns an array that contains
#### Example

```ts no-transpile
dispatch(api.util.selectInvalidatedBy(state, ['Post']))
dispatch(api.util.selectInvalidatedBy(state, [{ type: 'Post', id: 1 }]))
dispatch(
api.util.selectInvalidatedBy(state, [
{ type: 'Post', id: 1 },
{ type: 'Post', id: 4 },
])
)
const entries = api.util.selectInvalidatedBy(state, ['Post'])
const entries = api.util.selectInvalidatedBy(state, [{ type: 'Post', id: 1 }])
const entries = api.util.selectInvalidatedBy(state, [
{ type: 'Post', id: 1 },
{ type: 'Post', id: 4 },
])
```

### `invalidateTags`
Expand Down Expand Up @@ -318,6 +316,39 @@ dispatch(
)
```

### `selectCachedArgsForQuery`

#### Signature

```ts no-transpile
function selectCachedArgsForQuery(
state: RootState,
queryName: QueryName
): Array<QueryArg>
```

- **Parameters**
- `state`: the root state
- `queryName`: a string matching an existing query endpoint name

#### Description

A function that can select arguments for currently cached queries.

The function accepts two arguments

- the root state and

- the name of the query

It returns an array that contains arguments used for each entry.

#### Example

```ts no-transpile
const args = api.util.selectCachedArgsForQuery(state, 'getPosts')
```

### `resetApiState`

#### Signature
Expand Down
4 changes: 4 additions & 0 deletions docs/rtk-query/api/created-api/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ type Api = {
originalArgs: any
queryCacheKey: string
}>
selectCachedArgsForQuery: (
state: FullState,
endpointName: EndpointName
) => Array<QueryArg>
resetApiState: ActionCreator<ResetAction>
getRunningQueryThunk(
endpointName: EndpointName,
Expand Down
27 changes: 26 additions & 1 deletion packages/toolkit/src/query/core/buildSelectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import type {
RootState as _RootState,
RequestStatusFlags,
QueryCacheKey,
QueryKeys,
QueryState,
} from './apiState'
import { QueryStatus, getRequestStatusFlags } from './apiState'
import type {
Expand Down Expand Up @@ -130,7 +132,12 @@ export function buildSelectors<
const selectSkippedQuery = (state: RootState) => defaultQuerySubState
const selectSkippedMutation = (state: RootState) => defaultMutationSubState

return { buildQuerySelector, buildMutationSelector, selectInvalidatedBy }
return {
buildQuerySelector,
buildMutationSelector,
selectInvalidatedBy,
selectCachedArgsForQuery,
}

function withRequestFlags<T extends { status: QueryStatus }>(
substate: T
Expand Down Expand Up @@ -238,4 +245,22 @@ export function buildSelectors<
})
)
}

function selectCachedArgsForQuery<QueryName extends QueryKeys<Definitions>>(
state: RootState,
queryName: QueryName
): Array<QueryArgFrom<Definitions[QueryName]>> {
return Object.values(state[reducerPath].queries as QueryState<any>)
.filter(
(
entry
): entry is Exclude<
QuerySubState<Definitions[QueryName]>,
{ status: QueryStatus.uninitialized }
> =>
entry?.endpointName === queryName &&
entry.status !== QueryStatus.uninitialized
)
.map((entry) => entry.originalArgs)
}
}
26 changes: 20 additions & 6 deletions packages/toolkit/src/query/core/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,16 @@ declare module '../apiTypes' {
originalArgs: any
queryCacheKey: string
}>

/**
* A function to select all arguments currently cached for a given endpoint.
*
* 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.
*/
selectCachedArgsForQuery: <QueryName extends QueryKeys<Definitions>>(
state: RootState<Definitions, string, ReducerPath>,
queryName: QueryName
) => Array<QueryArgFrom<Definitions[QueryName]>>
}
/**
* Endpoints based on the input endpoints provided to `createApi`, containing `select` and `action matchers`.
Expand Down Expand Up @@ -527,13 +537,17 @@ export const coreModule = (): Module<CoreModule> => ({

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

const { buildQuerySelector, buildMutationSelector, selectInvalidatedBy } =
buildSelectors({
serializeQueryArgs: serializeQueryArgs as any,
reducerPath,
})
const {
buildQuerySelector,
buildMutationSelector,
selectInvalidatedBy,
selectCachedArgsForQuery,
} = buildSelectors({
serializeQueryArgs: serializeQueryArgs as any,
reducerPath,
})

safeAssign(api.util, { selectInvalidatedBy })
safeAssign(api.util, { selectInvalidatedBy, selectCachedArgsForQuery })

const {
buildInitiateQuery,
Expand Down
33 changes: 33 additions & 0 deletions packages/toolkit/src/query/tests/buildSelector.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,37 @@ describe('buildSelector', () => {
const upperTitle = todoTitle.toUpperCase()
expectExactType<string>(upperTitle)
})
test.skip('selectCachedArgsForQuery typetest', () => {
interface Todo {
userId: number
id: number
title: string
completed: boolean
}

type Todos = Array<Todo>

const exampleApi = createApi({
reducerPath: 'api',
baseQuery: fetchBaseQuery({
baseUrl: 'https://jsonplaceholder.typicode.com',
}),
endpoints: (build) => ({
getTodos: build.query<Todos, string>({
query: () => '/todos',
}),
}),
})

const store = configureStore({
reducer: {
[exampleApi.reducerPath]: exampleApi.reducer,
other: () => 1,
},
})

expectExactType<string[]>(
exampleApi.util.selectCachedArgsForQuery(store.getState(), 'getTodos')
)
})
})

0 comments on commit 37c27ef

Please sign in to comment.