T
TanStack4y ago
dependent-tan

setQueriesData not updating the cached data.

I have a mutation that updates data of a user.
export const useUpdateUser = (userID: string | undefined, userData: UserData) => {
const navigate = useNavigate();
const queryClient = useQueryClient();

return useMutation<ResultUsers, Error>(
() => axios.put(`https://jsonplaceholder.typicode.com/users/${userID}`, userData)
.then(response => response.data),
{
onSuccess: (data) => {
console.log(data?.city);
queryClient.setQueriesData([users.fetchUsers, userID], data)
navigate(ROUTES.USERS);
}
}
);
};
export const useUpdateUser = (userID: string | undefined, userData: UserData) => {
const navigate = useNavigate();
const queryClient = useQueryClient();

return useMutation<ResultUsers, Error>(
() => axios.put(`https://jsonplaceholder.typicode.com/users/${userID}`, userData)
.then(response => response.data),
{
onSuccess: (data) => {
console.log(data?.city);
queryClient.setQueriesData([users.fetchUsers, userID], data)
navigate(ROUTES.USERS);
}
}
);
};
My mutation is successful, however the cached data is not updating at onSuccess. For example, If I change the users City the request is successful, but setQueriesData is not updating the cache. This is how the mutation happens when the user edits their profile.
const {
data: fetchedUserData
...
} = useFetchUser(userID);

const userData = {
city,
...
};

const {
mutateAsync: updateUserMutation
...
} = useUpdateUser(userID, userData);

const saveDataOnClickHandler = () => {
updateUserMutation();
};
const {
data: fetchedUserData
...
} = useFetchUser(userID);

const userData = {
city,
...
};

const {
mutateAsync: updateUserMutation
...
} = useUpdateUser(userID, userData);

const saveDataOnClickHandler = () => {
updateUserMutation();
};
This is how the users are fetched when all users are listed
const Users = (): JSX.Element => {
const {
data: fetchedUsersData
...
} = useFetchUsers();

return (
<>
<UsersContainer>
{fetchedUsersIsLoading && <Loading />}
{fetchedUsersIsError && <ErrorHandler errorMessage={fetchedUsersError.message} />}
{fetchedUsersData &&
<Table fetchedUsersData={fetchedUsersData} />
}
</>
);
};

export default Users;
const Users = (): JSX.Element => {
const {
data: fetchedUsersData
...
} = useFetchUsers();

return (
<>
<UsersContainer>
{fetchedUsersIsLoading && <Loading />}
{fetchedUsersIsError && <ErrorHandler errorMessage={fetchedUsersError.message} />}
{fetchedUsersData &&
<Table fetchedUsersData={fetchedUsersData} />
}
</>
);
};

export default Users;
6 Replies
complex-teal
complex-teal4y ago
Hi does the queryKey of your list of users match the queryKey passed to setQueriesData? I would say that the queryKey of the list of users should not contain a userID.
dependent-tan
dependent-tanOP4y ago
Yes, I think you are right. If I remove userID my app crashes as .map is unable to iterate over the object returned. map function:
{fetchedUsersData?.map((user: Users) => (
<TRs
key={user.id}
>
<TD>{user.username}</TD>
<TD>{user.name}</TD>
<TD>{user.company.name}</TD>
<TD>{user.address.city}</TD>
</TRs>
))}
{fetchedUsersData?.map((user: Users) => (
<TRs
key={user.id}
>
<TD>{user.username}</TD>
<TD>{user.name}</TD>
<TD>{user.company.name}</TD>
<TD>{user.address.city}</TD>
</TRs>
))}
object returned:
{
"streetName": "Kulas Light",
"zipCode": "92998-3874",
"city": "London",
"email": "Sincere@april.biz",
"phone": "1-770-736-8031 x56442",
"id": 1
}
{
"streetName": "Kulas Light",
"zipCode": "92998-3874",
"city": "London",
"email": "Sincere@april.biz",
"phone": "1-770-736-8031 x56442",
"id": 1
}
Here is an example in the sandbox
dependent-tan
dependent-tanOP4y ago
itsgoodby
CodeSandbox
fast-bird-4p1u08 - CodeSandbox
fast-bird-4p1u08 by itsgoodby using axios, react, react-dom, react-query, react-router, react-router-dom, react-scripts
complex-teal
complex-teal4y ago
Yes this is the expected behaviour. The onSuccess of the mutation concerns 1 user, whereas the queryKey users.fetchUsers references the query having all users as data. 2 ways (at least) to solve your issue 1- just invalidate users queries on mutation success. Simple but perform an extra request 2- iterate of all queries that contain the updated user and replace just the user (could be found by id I guess). More work but avoid the extra request. Note that this solution might become hard to maintain with a large number of queries Also 2 advises : - add ReactQueryDev tools to your app to see the queries and their data - update to Tanstack Query v4
dependent-tan
dependent-tanOP4y ago
Thanks. I think queryClient.invalidateQueries([users.fetchUsers]) is prob easiest and will work in a real world situation. Unfortunately for the API I am using, (https://jsonplaceholder.typicode.com/guide/) the resource will not be really updated on the server but it will be faked as if. So the request on invalidateQueries will be successful but not return the updated user.
complex-teal
complex-teal4y ago
ok then you would have to go through sol2 by manually updating the queries that contain the user

Did you find this page helpful?