3

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

1
  • Maybe the RTK Query Advanced part of the Redux tutorial can explain that a bit better? It goes into that in further detail. Commented Aug 24, 2022 at 15:02

1 Answer 1

6

In 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.

Sign up to request clarification or add additional context in comments.

3 Comments

But the request will be sent regardless. I have a hard time understanding why this really matters.
Imagine you have 100 users and you want to fetch user_1’s posts only. If you dont write a dynamic tag, it will fetch 100 users’ posts which is too much unnecessary heavy work
By fetch do you mean re-render? Because as far as I know, the request will be fired either way.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.