Mutations
Unlike useQuery
, useMutation
returns a tuple. The first item in the tuple is the trigger
function and the second element contains an object with status
, error
, and data
. Additionally, useMutation
also makes internalQueryArgs
, originalArgs
,
and endpoint
available for inspection.
Unlike the useQuery
hook, the useMutation
hook doesn't execute automatically. To run a mutation you have to call the trigger function returned as the first tuple value from the hook.
info
Notice the onStart
, onSuccess
, onError
methods? Be sure to check out how they can be used for optimistic updates
Type interfaces
Basic Mutation
This is a modified version of the complete example you can see at the bottom of the page to highlight the updatePost
mutation. In this scenario, a post is fetched with useQuery
, and then a EditablePostName
component is rendered that allows us to edit the name of the post.
Advanced mutations with revalidation
In the real world, it's very common that a developer would want to resync their local data cache with the server after performing a mutation (aka "revalidation"). RTK Query takes a more centralized approach to this and requires you to configure the invalidation behavior in your API service definition. Before getting started, let's cover some new terms used when defining an endpoint in a service:
Entities
For RTK Query, entities are just a name that you can give to a specific collection of data to control caching and invalidation behavior, and are defined in an entityTypes
argument. For example, in an application that has both Posts
and Users
, you would define entityTypes: ['Posts', 'Users']
when calling createApi
.
Provides
A query can provide entities to the cache. The provides
argument can both be an array of string
(such as ['Posts']
), {type: string, id?: string|number}
or a callback that returns such an array. That function will be passed the result as the first argument and the argument originally passed into the query
method as the second argument.
Invalidates
A mutation can invalidate specific entities in the cache. The invalidates
argument can both be an array of string
(such as ['Posts']
), {type: string, id?: string|number}
or a callback that returns such an array. That function will be passed the result as the first argument and the argument originally passed into the query
method as the second argument.
Scenarios and Behaviors
RTK Query provides a lot of flexibility for how you can manage the invalidation behavior of your service. Let's look at a few different scenarios:
Invalidating everything of a type
What to expect
When addPost
is triggered, it would cause each PostDetail
component to go back into a isFetching
state because addPost
invalidates the root entity, which causes every query that provides 'Posts' to be re-run. In most cases, this may not be what you want to do. Imagine if you had 100 posts on the screen that all subscribed to a getPost
query – in this case, you'd create 100 requests and send a ton of unnecessary traffic to your server, which we're trying to avoid in the first place! Even though the user would still see the last good cached result and potentially not notice anything other than their browser hiccuping, you still want to avoid this.
Selectively invalidating lists
Keep an eye on the provides
property of getPosts
- we'll explain why after.
Note about 'LIST' and
id
s
LIST
is an arbitrary string - technically speaking, you could use anything you want here, such asALL
or*
. The important thing when choosing a custom id is to make sure there is no possibility of it colliding with an id that is returned by a query result. If you have unknown ids in your query results and don't want to risk it, you can go with point 3 below.- You can add many entity types for even more control
[{ type: 'Posts', id: 'LIST' }, { type: 'Posts', id: 'SVELTE_POSTS' }, { type: 'Posts', id: 'REACT_POSTS' }]
- If the concept of using an
id
like 'LIST' seems strange to you, you can always add anotherentityType
and invalidate it's root, but we recommend using theid
approach as shown.
What to expect
When addPost
is fired, it will only cause the PostsList
to go into an isFetching
state because addPost
only invalidates the 'LIST' id, which causes getPosts
to rerun (because it provides that specific id). So in your network tab, you would only see 1 new request fire for GET /posts
. Once that resolves and assuming it returned updated data for ids 1, 2, and 3, the PostDetail
components would then rerender with the latest data.
Commented Posts Service
This is an example of a CRUD service for Posts. This implements the Selectively invalidating lists strategy and will most likely serve as a good foundation for real applications.