diff --git a/docs/rtk-query/api/created-api/api-slice-utils.mdx b/docs/rtk-query/api/created-api/api-slice-utils.mdx index 5ce2f72e07..c218e8b207 100644 --- a/docs/rtk-query/api/created-api/api-slice-utils.mdx +++ b/docs/rtk-query/api/created-api/api-slice-utils.mdx @@ -197,6 +197,42 @@ dispatch( patchCollection.undo() ``` +### `removeQueryData` + +#### Signature + +```ts no-transpile +const removeQueryData = ( + endpointName: string, + args: any +) => ThunkAction; +``` + +- **Parameters** + - `endpointName`: a string matching an existing endpoint name + - `args`: a cache key, used to determine which cached dataset needs to be updated + +#### Description + +A Redux thunk that removes a specific query result from the cache. This immediately updates the Redux state with those changes. + +The thunk accepts two arguments: the name of the endpoint we are updating (such as `'getPost'`) and the appropriate query arg values to construct the desired cache key. + +#### Example + +```ts no-transpile +const patchCollection = dispatch( + api.endpoints.getPosts.initiate(undefined), + +// when cache data should be removed +dispatch( + api.util.removeQueryData( + 'getPosts', + undefined, + ), +) +``` + ### `prefetch` #### Signature diff --git a/packages/toolkit/src/query/core/buildThunks.ts b/packages/toolkit/src/query/core/buildThunks.ts index 40328f014f..486be682db 100644 --- a/packages/toolkit/src/query/core/buildThunks.ts +++ b/packages/toolkit/src/query/core/buildThunks.ts @@ -198,6 +198,14 @@ export type UpsertQueryDataThunk< UnknownAction > +export type RemoveQueryDataThunk< + Definitions extends EndpointDefinitions, + PartialState, +> = >( + endpointName: EndpointName, + args: QueryArgFrom, +) => ThunkAction + /** * An object returned from dispatching a `api.util.updateQueryData` call. */ @@ -355,6 +363,22 @@ export function buildThunks< ) } + const removeQueryData: RemoveQueryDataThunk = + (endpointName, args) => (dispatch) => { + const endpointDefinition = endpointDefinitions[endpointName] + + const queryCacheKey = serializeQueryArgs({ + queryArgs: args, + endpointDefinition, + endpointName, + }) + + + return dispatch(api.internalActions.removeQueryResult({ + queryCacheKey + })) + } + const executeEndpoint: AsyncThunkPayloadCreator< ThunkResult, QueryThunkArg | MutationThunkArg, @@ -670,6 +694,7 @@ In the case of an unhandled error, no tags will be "provided" or "invalidated".` updateQueryData, upsertQueryData, patchQueryData, + removeQueryData, buildMatchThunkActions, } } diff --git a/packages/toolkit/src/query/core/module.ts b/packages/toolkit/src/query/core/module.ts index c237c7b298..fc6ace4123 100644 --- a/packages/toolkit/src/query/core/module.ts +++ b/packages/toolkit/src/query/core/module.ts @@ -5,6 +5,7 @@ import type { PatchQueryDataThunk, UpdateQueryDataThunk, UpsertQueryDataThunk, + RemoveQueryDataThunk, } from './buildThunks' import { buildThunks } from './buildThunks' import type { @@ -303,6 +304,22 @@ declare module '../apiTypes' { RootState > + /** + * A Redux thunk that removes a specific query result from the cache. This immediately updates the Redux state with those changes. + * + * The thunk accepts two arguments: the name of the endpoint we are updating (such as `'getPost'`) and the appropriate query arg values to construct the desired cache key. + * + * @example + * + * ```ts + * dispatch(api.util.removeQueryData('getPost', { id: 1 })) + * ``` + */ + removeQueryData: RemoveQueryDataThunk< + Definitions, + RootState + > + /** * A Redux action creator that can be dispatched to manually reset the api state completely. This will immediately remove all existing cache entries, and all queries will be considered 'uninitialized'. * @@ -502,6 +519,7 @@ export const coreModule = ({ patchQueryData, updateQueryData, upsertQueryData, + removeQueryData, prefetch, buildMatchThunkActions, } = buildThunks({ @@ -533,6 +551,7 @@ export const coreModule = ({ patchQueryData, updateQueryData, upsertQueryData, + removeQueryData, prefetch, resetApiState: sliceActions.resetApiState, }) diff --git a/packages/toolkit/src/query/tests/cacheCollection.test.ts b/packages/toolkit/src/query/tests/cacheCollection.test.ts index 936ae82044..cd8308ba18 100644 --- a/packages/toolkit/src/query/tests/cacheCollection.test.ts +++ b/packages/toolkit/src/query/tests/cacheCollection.test.ts @@ -156,6 +156,43 @@ describe(`query: await cleanup, keepUnusedDataFor set`, () => { }) }) +describe('removeCacheData', () => { + const { store, api } = storeForApi( + createApi({ + baseQuery: fetchBaseQuery({ baseUrl: 'https://example.com' }), + endpoints: (build) => ({ + query: build.query({ + query: () => '/success', + }), + }), + }), + ) + + test('removeQueryData no impact if queryCacheKey different', async () => { + const promise = store.dispatch(api.endpoints.query.initiate('arg')) + await promise + const initialResponse = api.endpoints.query.select('arg')(store.getState()) + expect(initialResponse.data).toBeDefined() + + store.dispatch(api.util?.removeQueryData('query', 'argThatIsDifferent')) + + const removedResult = api.endpoints.query.select('arg')(store.getState()) + expect(removedResult.data).toBeDefined() + }) + + test('removeQueryData removes data of matching queryCacheKey', async () => { + const promise = store.dispatch(api.endpoints.query.initiate('arg')) + await promise + const initialResponse = api.endpoints.query.select('arg')(store.getState()) + expect(initialResponse.data).toBeDefined() + + store.dispatch(api.util?.removeQueryData('query', 'arg')) + + const removedResult = api.endpoints.query.select('arg')(store.getState()) + expect(removedResult.data).toBeUndefined() + }) +}) + function storeForApi< A extends { reducerPath: 'api'