T
TanStack•3y ago
adverse-sapphire

Using MutationCache to determine if a mutation function should run

I am trying to define a mutationKey in a useMutation hook and use the mutationCache to determine if a mutation has ran before. However, it is not working the way I expect it to work whenever the key changes due to the useMutation never unmounted. I am wondering if there is a better way to do this. This hook is used everywhere in the app so it has to work "globally". Thanks!
const useMutationTrack = (key: string) => {
const queryClient = useQueryClient()

return useMutation({
mutationKey: ['mutations', { key }],
mutationFn: () => {
const trackedBefore =
queryClient.getMutationCache().find({mutationKey:['mutations', { key }]})?.state?.status ===
'success'
if (trackedBefore) return Promise.resolve()

... other logic
}
})
}
const useMutationTrack = (key: string) => {
const queryClient = useQueryClient()

return useMutation({
mutationKey: ['mutations', { key }],
mutationFn: () => {
const trackedBefore =
queryClient.getMutationCache().find({mutationKey:['mutations', { key }]})?.state?.status ===
'success'
if (trackedBefore) return Promise.resolve()

... other logic
}
})
}
8 Replies
vicious-gold
vicious-gold•3y ago
Can you show a reproduction where this doesn't work?
adverse-sapphire
adverse-sapphireOP•3y ago
adverse-sapphire
adverse-sapphireOP•3y ago
The actual app's logic is a bit different than the one below where the key is actually coming from const { store_id } = useUser() query where the store_id changes based on certain actions. To reproduce the issue I was seeing: 1) click "click me" once 2) click "click me" again 3" click "update state" to change the key used for the mutationKey 4) click "click me" again <-- this is where I was expecting trackedBefore to be false
No description
adverse-sapphire
adverse-sapphireOP•3y ago
Please let me know if there is a better way to handle it if this is incorrect, thank you! 😀
vicious-gold
vicious-gold•3y ago
I think the problem is when you click update state, you are changing the mutationKey of the currently observing mutation. if you then click update state again, you'll see three entries in the mutation cache: - one with key abc and status success (from the first click) - one with key efg and status success (this is from the second click, where it originally ran as key abc, but was then changed to efg) - one with key efg and status loading (the last click) I can't really say if this is a bug in react-query. When your component re-renders with the new key, we update the options of the current mutation. I implemented this one month ago, as a fix for a bug with stale closures in the callbacks: - https://github.com/TanStack/query/pull/5085 maybe the solution is to only update the options of the mutation if the key hasn't changed 🤔
GitHub
fix(core): make sure mutations get updated options by TkDodo · Pull...
this fixes an issue around stale closures where callbacks are not updated, thus are called with wrong values in the closure fixes #5056
adverse-sapphire
adverse-sapphireOP•3y ago
Yep that’s what I think is happening too, thanks for confirming! @TkDodo 🔮 Do you think it makes sense to only update the options if the key hasn't changed? I think one of my teammate was relying on that behavior in 4.25. I can look into opening a PR as well! Hm this is only an issue when we have a page where the mutation gets called for an unauthenticated user and then the user logs in or signs up via a modal on the same page. What if we manually clear the mutation cache when a user logs in? queryClient.getMutationCache().clear()? We don’t really use the mutation cache that often, was wondering if this approach has any downside.
vicious-gold
vicious-gold•3y ago
yeah that's a good approach. I'm still thinking that only updating the options if the key hasn't changed feels right
adverse-sapphire
adverse-sapphireOP•3y ago
Thanks a lot!

Did you find this page helpful?