I am using react/redux and here are the user endpoints, as you can see I have a getUsers and also getSingleUser. in my app, when I first go to the usersList page which uses the getUsers Query, all the users are fetched and provided a tag, but when I click on each individual user to go to the singleUser page which uses getSingleUser, I can see that redux is not reading the user data from the previusly cached tags and it’s re-fetching the user again, and providing it another tag, so what would happen is that now I have to tags for the same user (65e0ef744995aa9b6b8d1af4[0] and 65e0ef744995aa9b6b8d1af4[1]), one for the user that was fetched with getUsers and one for the one that was fetched with getSingleUser.
how can I fix this issue?
import { apiSlice } from "../apiSlice";
const userApiSlice = apiSlice.injectEndpoints({
endpoints: (builder) => ({
getUsers: builder.query ({
query: () => 'user',
providesTags: (result, error, context) => {
if (!error && result) {
return [{type: 'User', id: 'LIST'}, ...result.users.map(user => ({type: 'User', id: user._id}))]
} else {
return [{type: 'User', id: 'LIST'}]
}
}
}),
getSingleUser: builder.query ({
query: (id) => `user/${id}`,
providesTags: (result, error, context) => {
if (result && !error) {
return [{type: 'User', id: result.user._id}]
}
}
}),
getUserBySearch: builder.query ({
query: (search = '') => `user/search?q=${search}`,
providesTags: (result, error, context) => {
if (!error && result) {
return [{type: 'User', id: 'LIST'}, ...result.users.map(user => ({type: 'User', id: user._id}))]
} else {
return [{type: 'User', id: 'LIST'}]
}
},
keepUnusedDataFor: 5,
}),
createUser: builder.mutation({
query: (credentials) => ({
url: 'user',
method: 'POST',
body: credentials,
}),
invalidatesTags: [{type: 'User', id: 'LIST'}]
}),
deleteUser: builder.mutation ({
query: (id) => ({
url: `user/${id}`,
method: 'DELETE'
}),
invalidatesTags: (result, error, context) => {
console.log(`this is result: ${JSON.stringify(result)}`)
if (result?.id && !error) {
return [{type: 'User', id: result.id}]
}
}
})
})
})
export const {
useGetUsersQuery,
useGetSingleUserQuery,
useGetUserBySearchQuery,
useCreateUserMutation,
useDeleteUserMutation
} = userApiSlice;
I excpect to after using getUsers Query, to get SingleUser data immediately without having to wait.
btw, I am using redux devtools, that’s how I know two intances of the same tag is being made
2
Answers
The getSingleUser isn’t going to be able to get the values from a different endpoint’s cache. Instead, whenever you change something that invalidates the tag for a user, it will cause a refetch of both the query that fetches the collection and the individual query for that one tag.
Probably a better way to handle this is to provide the users you already got into something that displays via dependency injection (component props), and then if you need it somewhere you won’t have all the users, use your getSingleUser hook in a level above the View that displays data for just that user. If you build your View just to display the user data and not care where that comes from, you can handle getting that data in the parent component. Separation of concerns FTW!
Each endpoint is effectively its own entity, its own cache is used. Endpoints are not aware of the cached results of other endpoints. The behavior you describe sounds like applied optimistic/pessimistic updates. The
getUsers
endpoint can update the cache of other endpoints upon success.See Manual Cache Updates, specifically Creating new cache entries or replacing existing ones for details.
Use the
getUser
endpoint’sonQueryStarted
method to update thegetSingleUser
endpoint’s cache, effectively pre-populating that endpoint with user data by queryid
argument.Example: