I am following the official doc to learn RTK query. But, I am not sure what is the difference between doing the cache invalidation like this
getUsers: build.query<User[], void>({
query: () => '/users',
providesTags: ['User'],
}),
and this
providesTags: (result, error, arg) =>
result
? [...result.map(({ id }) => ({ type: 'Post' as const, id })), 'Post']
: ['Post'],
The doc explains For more granular control over the provided data, provided tags can have an associated id. This enables a distinction between 'any of a particular tag type', and a specific instance of a particular tag type'.
But, I have no idea what it means. Same for the invalidatesTags
I am following the official doc to learn RTK query. But, I am not sure what is the difference between doing the cache invalidation like this
getUsers: build.query<User[], void>({
query: () => '/users',
providesTags: ['User'],
}),
and this
providesTags: (result, error, arg) =>
result
? [...result.map(({ id }) => ({ type: 'Post' as const, id })), 'Post']
: ['Post'],
The doc explains For more granular control over the provided data, provided tags can have an associated id. This enables a distinction between 'any of a particular tag type', and a specific instance of a particular tag type'.
But, I have no idea what it means. Same for the invalidatesTags
- Maybe the RTK Query Advanced part of the Redux tutorial can explain that a bit better? It goes into that in further detail. – phry Commented Aug 24, 2022 at 15:02
1 Answer
Reset to default 6In the first case, you are providing a hardcoded tag name to fetch users. Let's assume under users you want to show their posts and you also have 'Add a Post' button to send a mutation to add a post. Instead of function, what would happen if we passed a hardcoded tag
providesTags: ['Post'],
When we provide tags for queries, every query will get a tag name kinda id. So when we send a post request to the server with ADD POST
mutation, we pass invalidatesTags:["Post"]
to the mutation, so after the mutation is done, the mutation will go look for queries with 'Post'
tag name, it will think that query is stale now so it will run that query with the provided tag again and your app store will be populated with the fresh data. this is how invalidating the cache works.
Assume that you have 10 users on your page and you clicked on Add a Post
button for the User-1. It will run the 'ADD POST` mutation then it will go and look for provided "POST" tag and will invalidate that query and re-fetch data. In your case, running mutation for User-1, will go run the get query for all 10 users because all user posts get query is tagged with 'Post'. But you mutated only User-1's posts therefore you should be re-fetching only User-1 posts query.
This is why we pass a function so that we can DYNAMICALLY
define the tag name. That function takes 3 arguments: (the error ar is clear)
result
is the posts in the store.
arg
is the argument that you have passed when you call the query. Let' say you have called getUserPostQuery(user)
, you can access this user
inside the function with the arg
providesTags: (result, error, arg) =>
// i believe it should have been `arg.id`. otherwise id would be undefined. we are fetching user's post
// result would be the user's posts
result
? [...result.map(({ id }) => ({ type: 'Post' as const, id:arg.id })), 'Post']
: ['Post'],
So we have dynamically defined our tag name as
{ type: 'Post' as const, id:arg.id }
You have to define your invalidatesTags
property with the same function signature to create a dynamic tag name to invalidate.
With this implementation, If you mutate the User-1's post now, redux will run the get query only for User-1.