T
TanStack2y ago
deep-jade

useMutation onSuccess trying to add new row of data to UI, not working

I am a newbie with this library. Attempting to implement my first useMutation. Everything is working correctly on the backend. Now on the front, I want to reflect the new ingredient that was just added in the table. I read on their site that the usual practice is passing back the newly added entry after adding something, so no extra network calls needed. I am passing the new ingredient back and I can see it in the data. But the ingredients table is not updating. I don't understand react-query enough to understand what variables is or where it is coming from. But I'm thinking one issue or maybe the issue is that the id in variables is blank. Here is my useMutation code:
const { mutateAsync: insertIngredientMutation, isLoading } = useMutation({
mutationFn: insertIngredient,
onSuccess: (data, variables) => {
console.log({ data, variables });
queryClient.setQueryData(
['ingredients', { id: variables.id }],
data
);
}
});
const { mutateAsync: insertIngredientMutation, isLoading } = useMutation({
mutationFn: insertIngredient,
onSuccess: (data, variables) => {
console.log({ data, variables });
queryClient.setQueryData(
['ingredients', { id: variables.id }],
data
);
}
});
11 Replies
deep-jade
deep-jadeOP2y ago
Updates from Mutation Responses | TanStack Query Docs
When dealing with mutations that update objects on the server, it's common for the new object to be automatically returned in the response of the mutation. Instead of refetching any queries for that item and wasting a network call for data we already have, we can take advantage of the object returned by the mutation function and update the exis...
vicious-gold
vicious-gold2y ago
Pretty sure variables is what you call mutateAysnc(...) with and in that case if you're inserting you probably don't have an id. That id should come from your data result
deep-jade
deep-jadeOP2y ago
Oh, so here is where I'm calling the mutateAsync: insertIngredientMutation(editingIngredient).then((r) => console.log(r)); so editingIngredient should have an id?
vicious-gold
vicious-gold2y ago
editing would, yeah. But your original code snippet was insertIngredientMutation
deep-jade
deep-jadeOP2y ago
I'm renaming that function
vicious-gold
vicious-gold2y ago
If you have an id being passed into the mutation then that should work assuming your queryKeys match
deep-jade
deep-jadeOP2y ago
aw yep, id is blank in that object too Seems hacky to do this code and on the front end:
const addIngredient = () => {
setAddingIngredient(true);
console.log({ ingIDs: ingredients.map((i) => i.id) });
const ingIDs = ingredients.map((i) => i.id);
const largestID = Math.max(...ingIDs);
const nextID = largestID +1;
...
const addIngredient = () => {
setAddingIngredient(true);
console.log({ ingIDs: ingredients.map((i) => i.id) });
const ingIDs = ingredients.map((i) => i.id);
const largestID = Math.max(...ingIDs);
const nextID = largestID +1;
...
I feel like I should be able to add a new ingredient without figuring out the id ahead of time? Am I going about it wrong?
vicious-gold
vicious-gold2y ago
Yeah you shouldn't determine the id that's for your server/database to handle
deep-jade
deep-jadeOP2y ago
yeah, thats what I was thinking so then how do I get that variables object to have a filled in id?
vicious-gold
vicious-gold2y ago
That's really not a react-query question tbh. If you're editing your data should contain ids, if you're inserting your API result should provide that id. If you want to use one mutation for both you could do something like queryClient.setQueryData(['todo', { id: data.id ?? variables.id }], data)
deep-jade
deep-jadeOP2y ago
what do you mean for both? I'm only doing one mutation. wondering if I have to do something like this?
queryClient.setQueryData(
['ingredients', { id: data.id ?? variables.id }],
(oldData) => [...oldData, data]);
queryClient.setQueryData(
['ingredients', { id: data.id ?? variables.id }],
(oldData) => [...oldData, data]);
I did verify that this code does do what I want:
onSuccess: (data, variables) => {
console.log({ data, variables });
queryClient.invalidateQueries(['ingredients']);
onSuccess: (data, variables) => {
console.log({ data, variables });
queryClient.invalidateQueries(['ingredients']);
I guess its my fallback if I can't get the setQueryData to work Finally got it to work with this code:
onSuccess: (data) => {
queryClient.setQueryData(['ingredients'], (prevData: any) => [
...prevData,
data[0]
]);
}
onSuccess: (data) => {
queryClient.setQueryData(['ingredients'], (prevData: any) => [
...prevData,
data[0]
]);
}
Thanks for your help!

Did you find this page helpful?