API Slices: Utilities
The API slice object includes various utilities that can be used for cache management, such as implementing optimistic updates, as well implementing server side rendering.
These are included in a util
field inside the slice object.
updateQueryData
Signature
const updateQueryData = (
endpointName: string,
args: any,
updateRecipe: (draft: Draft<CachedState>) => void
) => ThunkAction<PatchCollection, PartialState, any, AnyAction>;
interface PatchCollection {
patches: Patch[];
inversePatches: Patch[];
undo: () => void;
}
- Parameters
endpointName
: a string matching an existing endpoint nameargs
: an argument matching that used for a previous query call, used to determine which cached dataset needs to be updatedupdateRecipe
: an Immerproduce
callback that can apply changes to the cached state
Description
A Redux thunk action creator that, when dispatched, creates and applies a set of JSON diff/patch objects to the current state. This immediately updates the Redux state with those changes.
The thunk action creator accepts three arguments: the name of the endpoint we are updating (such as 'getPost'
), any relevant query arguments, and a callback function. The callback receives an Immer-wrapped draft
of the current state, and may modify the draft to match the expected results after the mutation completes successfully.
The thunk returns an object containing {patches: Patch[], inversePatches: Patch[], undo: () => void}
. The patches
and inversePatches
are generated using Immer's produceWithPatches
method.
This is typically used as the first step in implementing optimistic updates. The generated inversePatches
can be used to revert the updates by calling dispatch(patchQueryData(endpointName, args, inversePatches))
. Alternatively, the undo
method can be called directly to achieve the same effect.
Note that the first two arguments (endpointName
and args
) are used to determine which existing
cache entry to update. If no existing cache entry is found, the updateRecipe
callback will not run.
Example 1
const patchCollection = dispatch(
api.util.updateQueryData('getPosts', undefined, (draftPosts) => {
draftPosts.push({ id: 1, name: 'Teddy' })
})
)
In the example above, 'getPosts'
is provided for the endpointName
, and undefined
is provided
for args
. This will match a query cache key of 'getPosts(undefined)'
.
i.e. it will match a cache entry that may have been created via any of the following calls:
api.endpoints.getPosts.useQuery()
useGetPostsQuery()
useGetPostsQuery(undefined, { ...options })
dispatch(api.endpoints.getPosts.initiate())
dispatch(api.endpoints.getPosts.initiate(undefined, { ...options }))
Example 2
const patchCollection = dispatch(
api.util.updateQueryData('getPostById', 1, (draftPost) => {
draftPost.name = 'Lilly'
})
)
In the example above, 'getPostById'
is provided for the endpointName
, and 1
is provided
for args
. This will match a query cache key of 'getPostById(1)'
.
i.e. it will match a cache entry that may have been created via any of the following calls:
api.endpoints.getPostById.useQuery(1)
useGetPostByIdQuery(1)
useGetPostByIdQuery(1, { ...options })
dispatch(api.endpoints.getPostById.initiate(1))
dispatch(api.endpoints.getPostById.initiate(1, { ...options }))
patchQueryData
Signature
const patchQueryData = (
endpointName: string,
args: any
patches: Patch[]
) => ThunkAction<void, PartialState, any, AnyAction>;
- Parameters
endpointName
: a string matching an existing endpoint nameargs
: a cache key, used to determine which cached dataset needs to be updatedpatches
: an array of patches (or inverse patches) to apply to cached state. These would typically be obtained from the result of dispatchingupdateQueryData
Description
A Redux thunk action creator that applies a JSON diff/patch array to the cached data for a given query result. This immediately updates the Redux state with those changes.
The thunk action creator accepts three arguments: the name of the endpoint we are updating (such as 'getPost'
), any relevant query arguments, and a JSON diff/patch array as produced by Immer's produceWithPatches
.
This is typically used as the second step in implementing optimistic updates. If a request fails, the optimistically-applied changes can be reverted by dispatching patchQueryData
with the inversePatches
that were generated by updateQueryData
earlier.
In cases where it is desired to simply revert the previous changes, it may be preferable to call the undo
method returned from dispatching updateQueryData
instead.
Example
const patchCollection = dispatch(
api.util.updateQueryData('getPosts', undefined, (draftPosts) => {
draftPosts.push({ id: 1, name: 'Teddy' })
})
)
// later
dispatch(
api.util.patchQueryData('getPosts', undefined, patchCollection.inversePatches)
)
// or
patchCollection.undo()
prefetch
Signature
type PrefetchOptions = { ifOlderThan?: false | number } | { force?: boolean };
const prefetch = (
endpointName: string,
arg: any,
options: PrefetchOptions
) => ThunkAction<void, any, any, AnyAction>;
Parameters
endpointName
: a string matching an existing endpoint nameargs
: a cache key, used to determine which cached dataset needs to be updatedoptions
: options to determine whether the request should be sent for a given situation:ifOlderThan
: if specified, only runs the query if the difference betweennew Date()
and the lastfulfilledTimeStamp
is greater than the given value (in seconds)force
: iftrue
, it will ignore theifOlderThan
value if it is set and the query will be run even if it exists in the cache.
Description
A Redux thunk action creator that can be used to manually trigger pre-fetching of data.
The thunk action creator accepts three arguments: the name of the endpoint we are updating (such as 'getPost'
), any relevant query arguments, and a set of options used to determine if the data actually should be re-fetched based on cache staleness.
React Hooks users will most likely never need to use this directly, as the usePrefetch
hook will dispatch the thunk action creator result internally as needed when you call the prefetching function supplied by the hook.
Example
dispatch(api.util.prefetch('getPosts', undefined, { force: true }))
invalidateTags
Signature
const invalidateTags = (
tags: Array<TagTypes | FullTagDescription<TagTypes>>
) => ({
type: string,
payload: tags,
})
- Parameters
tags
: an array of tags to be invalidated, where the providedTagType
is one of the strings provided to thetagTypes
property of the api. e.g.[TagType]
[{ type: TagType }]
[{ type: TagType, id: number | string }]
Description
A Redux action creator that can be used to manually invalidate cache tags for automated re-fetching.
The action creator accepts one argument: the cache tags to be invalidated. It returns an action with those tags as a payload, and the corresponding invalidateTags
action type for the api.
Dispatching the result of this action creator will invalidate the given tags, causing queries to automatically re-fetch if they are subscribed to cache data that provides the corresponding tags.
Example
dispatch(api.util.invalidateTags(['Post']))
dispatch(api.util.invalidateTags([{ type: 'Post', id: 1 }]))
dispatch(
api.util.invalidateTags([
{ type: 'Post', id: 1 },
{ type: 'Post', id: 'LIST' },
])
)
resetApiState
Signature
const resetApiState = () => ({
type: string,
payload: undefined,
})
Description
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'.
Note that hooks also track state in local component state and might not fully be reset by resetApiState
.
Example
dispatch(api.util.resetApiState())
getRunningOperationPromises
Signature
getRunningOperationPromises: () => Array<Promise<unknown>>
Description
A function that returns all promises for running queries and mutations.
This is useful for SSR scenarios to await everything triggered in any way, including via hook calls,
or manually dispatching initiate
actions.
await Promise.all(api.util.getRunningOperationPromises())
getRunningOperationPromise
Signature
getRunningOperationPromise: <EndpointName extends QueryKeys<Definitions>>(
endpointName: EndpointName,
args: QueryArgFrom<Definitions[EndpointName]>
) =>
| QueryActionCreatorResult<Definitions[EndpointName]>
| undefined
getRunningOperationPromise: <EndpointName extends MutationKeys<Definitions>>(
endpointName: EndpointName,
fixedCacheKeyOrRequestId: string
) =>
| MutationActionCreatorResult<Definitions[EndpointName]>
| undefined
Description
A function that returns a single promise for a given endpoint name + argument combination,
if it is currently running. If it is not currently running, the function returns undefined
.
When used with mutation endpoints, it accepts a fixed cache key or request ID rather than the argument.
This is primarily added to add experimental support for suspense in the future.
It enables writing custom hooks that look up if RTK Query has already got a running promise
for a certain endpoint/argument combination, and retrieving that promise to throw
it.