updateQueryData signature and parameters
updateQueryData is a Redux thunk action creator with signature: const updateQueryData = (endpointName: string, arg: any, updateRecipe: (draft: Draft<CachedState>) => void, updateProvided?: boolean) => ThunkAction<PatchCollection, PartialState, any, AnyAction>. Parameters are: endpointName (a string matching an existing endpoint name), arg (an argument matching that used for a previous query call, used to determine which cached dataset needs to be updated), updateRecipe (an Immer produce callback that can apply changes to the cached state), updateProvided (a boolean indicating whether the endpoint's provided tags should be re-calculated based on the updated cache, defaults to false).
updateQueryData return value structure
updateQueryData returns a thunk that produces an object with structure: interface PatchCollection { patches: Patch[], inversePatches: Patch[], undo: () => void }. The patches and inversePatches are generated using Immer's produceWithPatches method.
updateQueryData behavior with no matching cache entry
If no existing cache entry is found when using updateQueryData, the updateRecipe callback will not run.
updateQueryData example with undefined arg
Example: const patchCollection = dispatch(api.util.updateQueryData('getPosts', undefined, (draftPosts) => { draftPosts.push({ id: 1, name: 'Teddy' }) })). Providing 'getPosts' for endpointName and undefined for arg will match a query cache key of 'getPosts(undefined)', which matches cache entries created via api.endpoints.getPosts.useQuery(), useGetPostsQuery(), useGetPostsQuery(undefined, { ...options }), dispatch(api.endpoints.getPosts.initiate()), or dispatch(api.endpoints.getPosts.initiate(undefined, { ...options })).
updateQueryData example with arg
Example: const patchCollection = dispatch(api.util.updateQueryData('getPostById', 1, (draftPost) => { draftPost.name = 'Lilly' })). Providing 'getPostById' for endpointName and 1 for arg will match a query cache key of 'getPostById(1)', which matches cache entries created via api.endpoints.getPostById.useQuery(1), useGetByIdQuery(1), useGetByIdQuery(1, { ...options }), dispatch(api.endpoints.getPostById.initiate(1)), or dispatch(api.endpoints.getPostById.initiate(1, { ...options })).
RTK Query supports manual cache manipulation
RTK Query allows manual manipulation of the cache to update query data directly.
RTK Query can patch existing query data from middleware
RTK Query allows easily invalidating entities or patching existing query data via util.updateQueryData from middleware.
queryThunk.fulfilled merge functionality
When queryThunk.fulfilled is handled and a merge function is provided, if substate.data already exists, the merge function is called with draftSubstateData, payload, arg.originalArgs, baseQueryMeta, fulfilledTimeStamp, and requestId. The result is assigned to substate.data. If no data exists, the payload is cached directly as substate.data.
updateQueryData thunk purpose and behavior
updateQueryData is a thunk exported from api.utils that updates an already existing cache entry. It is strictly intended to perform updates to existing cache entries, not create new entries. If an updateQueryData thunk action is dispatched and the endpointName + args combination does not match any existing cache entry, the provided recipe callback will not be called, and no patches or inversePatches will be returned.
updateQueryData use cases
Use cases for manual update of cache entries with updateQueryData include: providing immediate feedback to the user when a mutation is attempted; after a mutation, updating a single item in a large list of items that is already cached, rather than re-fetching the whole list; debouncing a large number of mutations with immediate feedback as though they are being applied, followed by a single request sent to the server to update the debounced attempts.
General manual cache update example with updateQueryData
import { api } from './api'
import { useAppDispatch } from './store/hooks'
function App() {
const dispatch = useAppDispatch()
function handleClick() {
const patchCollection = dispatch(
api.util.updateQueryData('getPosts', undefined, (draftPosts) => {
draftPosts.push({ id: 1, name: 'Teddy' })
}),
)
}
return <button onClick={handleClick}>Add post to cache</button>
}
This example shows how to manually update the cache for the getPosts endpoint with no argument (undefined) using dispatch in a React component.
updateCachedData Immer integration
The updateCachedData utility in onCacheEntryAdded is powered by Immer and allows mutating a draft of the current cache value. RTK Query then dispatches an action that applies a diffed patch based on those changes.