blog/mastering-mutations-in-react-query #70
Replies: 85 comments 101 replies
-
Another great post! You're on 🔥, congrats! I have a question about some questions about this topic:
|
Beta Was this translation helpful? Give feedback.
-
No, I don’t think it’s a bad practice. Personally, I try to keep the mutation as close to where it’s needed (e.g. the button that performs it) and I usually don’t need the result anywhere else, because the mutation influences associated queries, and I use those everywhere :) |
Beta Was this translation helpful? Give feedback.
-
thanks for awesome post! i have a question @TkDodo, i prefer use
so, my question is...
|
Beta Was this translation helpful? Give feedback.
-
@JaeYeopHan For global error handling, I would set an |
Beta Was this translation helpful? Give feedback.
-
@TkDodo oh thanks! :)
that's the part I missed. |
Beta Was this translation helpful? Give feedback.
-
@JaeYeopHan unhandled promise rejections occur when the browser sees a failed Promise without a |
Beta Was this translation helpful? Give feedback.
-
Awesome post, thanks for sharing! Returning a |
Beta Was this translation helpful? Give feedback.
-
@TkDodo Thanks for the awesome article, I guess I have been doing mutations all wrong! I always used mutateAsync so I could await, get the result and then call the next mutation. How would you solve a typical case like that? |
Beta Was this translation helpful? Give feedback.
-
Dependent mutations can basically be solved in 3 different ways. It's a pity I didn't get to include that in the article, I kinda forgot about it 😅 :
advantage would be one mutation with one loading state. disadvantage would be you can't easily trigger them separately if you'd need to.
a bit boilerplate-y and you'd need to combine loading states very likely
separated, but still quite concise. will get messy with more than 2 mutations, and the end-result would only be available in the onSuccess callback of the second mutation if you need it |
Beta Was this translation helpful? Give feedback.
-
Hi, thanks I figured it will be one of those 3, still torn on what should be used best. ATM we use option 2 (without the try / catch woopsie), but we also so a couple of issues with toasters flying in too early and page redirects to newly created resources not always working (cache is being updated but page is already redirecting) The last option also seems a bit messy but I understand the reasoning. What I'm thinking now is having 3 independent useMutation hook wrappers and then wrap those in a component specific hook also using useMutation, not sure how that will pan out but going to try that. The benefit would be that I still can call the hooks independently but I can also call them in one go. Thanks for the reply! |
Beta Was this translation helpful? Give feedback.
-
how can I mock useIsMutating hook with msw or jest for fetching state of particular mutationKey? |
Beta Was this translation helpful? Give feedback.
-
@hedaukartik if you use |
Beta Was this translation helpful? Give feedback.
-
@TkDodo my use-case was to show loader in different component and not in the component where my In the docs, PS. MSW is smooth with react-query. Thanks for your amazing articles out there. |
Beta Was this translation helpful? Give feedback.
-
Beautiful article, enjoyed all the way through including comments. |
Beta Was this translation helpful? Give feedback.
-
Hey, many thanks for your awesome articles! They really helped me a lot to learn react-query more deeply! Unfortunately I'm kinda stuck here with a mutation and I can't figure out how to make this work, if some of you guys had already this scenario and could give some hints it would help me a lot. So I have built my mutation: export const useAddPeer = (
portfolioId: PortfolioId,
): UseMutationResult<PortfolioWithPeers, unknown, PeerRequestBody, unknown> => {
const queryClient = useQueryClient();
return useMutation(
(newPeer: PeerRequestBody) =>
handleRequest<PortfolioResponse, AddPeersIntoPortfolioRequestBody>({
url: `${API_PATH}/${portfolioId}/peers`,
method: 'PUT',
payload: {
peers: [newPeer],
},
}),
{
onSuccess: () => queryClient.invalidateQueries('portfolio-overview'),
},
);
}; And here is how I call it: const addPeer = useAddPeer(activePortfolio.id);
const handleAddPeer = (newPeer: PeerRequestBody) => () => addPeer.mutate(newPeer);
<Box
onClick={handleAddPeer({
tickerId: ticker.id,
isFavorite: false,
})}
> ... </Box> and my And here is how my export const usePortfolioOverview = (
portfolioId: PortfolioId,
): UseQueryResult<PortfolioOverviewResponse, Error> =>
useQuery<PortfolioOverviewResponse, Error>(
['portfolio-overview', portfolioId],
() =>
handleRequest({
url: `${API_PATH}/${portfolioId}/overview`,
method: 'GET',
}),
{
enabled: !!portfolioId,
},
); basically the logic is -> I'm inside another component which I search for the "peers" and after clicking on it, it's added to the portfolio, which then maps all peers and display all of them in a list, and that's what I'm trying here, to mutate this list after adding a new peer to it. |
Beta Was this translation helpful? Give feedback.
-
Great article @TkTodo. This may be just preference but when creating a custom hook, is it better to return the mutation or only the parts you want to expose?
I feel like it's a bit cleaner as you can use the function like |
Beta Was this translation helpful? Give feedback.
-
Great writing 🎉 Just need to ask you about invalidation, you mentioned that:
What if I need to force an inactive query to be refetched because I don't want the user to wait for it when he reaches to that UI part that has the inactive observer, is this possible with react-query? |
Beta Was this translation helpful? Give feedback.
-
Thanks for a great topic @TkDodo <3 May I ask you a question: |
Beta Was this translation helpful? Give feedback.
-
I guess if there is an options to use it is good to not have logic in useEffect, because with react 18 in dev mode it is triggered twice, don't sure maybe it will be default behavior for production in future for some cases. So i think it is good to place the logic of side effects inside mutation's onSuccess/onError/onSettled handlers and do all you need there directly than doing it indirectly via useEffect. useMutation({
queryFn: () => getCategories(),
onSuccess: () => {
handleClose();
},
onError: () => {
toast.error('Ups');
},
}); |
Beta Was this translation helpful? Give feedback.
-
Hi @TkDodo, There is a scenario where i am failing. I open app and goes inside some screen then i turned on internet. At that point i want to resume mutation. I am successfully in resuming mutation by default in all case. Is there a way to resume mutation after app gets opened and then resuming mutation manually if it fails to resume (if initailly internet is not there but later we get internet connectivity) Thanks |
Beta Was this translation helpful? Give feedback.
-
I'm a bit confused about whether one should use onError and/or onSuccess callbacks when using mutateAsync? Namely, I notice that the function signature for mutationAsync allows the use of these callbacks, but I don't see any examples (in this blog or elsewhere) where they are used in the mutateAsync options. When I try using onSuccess and onError in useMutation and mutateAsync I notice the following:
Does this seem accurate? |
Beta Was this translation helpful? Give feedback.
-
Awesome post, I have question relating to dependent mutations. I know you have given an answer to that, but I would like to know what will you suggest about the following scenario. This pattern is followed throughout the entire application. I was hoping for some kind composition pattern, where I can wrap my mutation hooks, and adjust the mutation function somehow. I am not sure how to approach this. Kindly let me know your thoughts. |
Beta Was this translation helpful? Give feedback.
-
Type '(formData: RegisterFormData) => Promise' has no properties in common with type 'UseMutationOptions<void, Error, RegisterFormData, unknown>'. what should i do? |
Beta Was this translation helpful? Give feedback.
-
Hi @TkDodo, maybe I'm just stupid, but I have a question regarding optimistic updates. What if a user were to mutate very quickly and the time it took to fetch was too long for it to get cancelled on time. For example, in a a todo list if a user created two todos very fast, but the time it took to create the first todo was too long before the refetch got cancelled by creating the second todo. I don't know if that makes sense, so i've created a codesandbox to illustrate what I mean. I've used the code from the docs as an example. https://codesandbox.io/p/sandbox/friendly-river-3ty6zr?file=%2Fsrc%2Findex.js%3A62%2C33 |
Beta Was this translation helpful? Give feedback.
-
Awesome blog :) I have a question regarding mutation hook, when you use async await refetchQueries in onSuccess lifecycle, |
Beta Was this translation helpful? Give feedback.
-
React Query waiting for promised returned by the callbacks is a great feature, but I'm wondering, how does this work with the callbacks on the mutate function? Will they fire only after the promises on the equivalent callbacks on useMutation have finished? For instance, I would want to make sure the invalidations have finished before running the code in my onSuccess callback on mutate(). |
Beta Was this translation helpful? Give feedback.
-
How do I stop mutateFn from continuing to run even if one of my requests fails? |
Beta Was this translation helpful? Give feedback.
-
Hi |
Beta Was this translation helpful? Give feedback.
-
So basically anything that affects the UI should be done in the mutate. if i want to set data to local storage i should do it in the useMutation? |
Beta Was this translation helpful? Give feedback.
-
Hi TkDodo, I hope you're doing well. I really love this React Query series. In v5, I'm facing a type issue in export const useAddPartner = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: addPartner,
onSuccess(data) {
queryClient.invalidateQueries({
queryKey: partnerKeys.all,
});
sheetClose();
toast.success(data?.message);
},
});
}; |
Beta Was this translation helpful? Give feedback.
-
Mastering Mutations in React Query | TkDodo's blog
Learn all about the concept of performing side effects on the server with React Query.
https://tkdodo.eu/blog/mastering-mutations-in-react-query?utterances=22c272992acbd295c16b127dAie0B3x1NqhQorEKRGvFH71aM5MGXVEjl9WD5QZk2FjzX1Df%2FkFTH3OXs%2BinSDdYvbJn6fzf77VJgjGGyG9yk2I3qyKrT3CxpNink9ZEvoWXCAFbJKwKTpAZCv4%3D
Beta Was this translation helpful? Give feedback.
All reactions