T
TanStack•3y ago
flat-fuchsia

Why does invalidateQueries() break mutate()'s onSuccess() sometimes, but not mutateAsync().then() ?

The short gist of the problem is code like this:
// userMutations.js
const useCreateUserMutation = () => {
const queryClient = useQueryClient()
return useMutation(resetStudentsProgress, {
onSuccess: () => queryClient.invalidateQueries(['users', 'list']), // returns a promise to onSuccess
})
}

// CreateUser.jsx
const createUserMutation = useCreateUserMutation()
const onSubmit = (values) => createUserMutation.mutate(values, {
onSuccess: () => {
window.alert('User created successfully') // <- NEVER TRIGGERS
}
})
// userMutations.js
const useCreateUserMutation = () => {
const queryClient = useQueryClient()
return useMutation(resetStudentsProgress, {
onSuccess: () => queryClient.invalidateQueries(['users', 'list']), // returns a promise to onSuccess
})
}

// CreateUser.jsx
const createUserMutation = useCreateUserMutation()
const onSubmit = (values) => createUserMutation.mutate(values, {
onSuccess: () => {
window.alert('User created successfully') // <- NEVER TRIGGERS
}
})
I'm intentionally returning the result of invalidateQueries to the useMutation options onSuccess as that allows createUserMutation.isLoading to not resolve until both the user is created, AND stale users are succesully re-fetched again. This works fine in 99% of cases. However, I have a very small number of queries in a very large project that for some reason, hang and only trigger the useMutation's config onSuccess, but NOT the mutate() 's provided onSuccess option. I've debugged the issue and noticed interesting things like changing the code to this fixes the subsequent onSuccess:
// userMutations.js
const useCreateUserMutation = () => {
const queryClient = useQueryClient()
return useMutation(resetStudentsProgress, {
onSuccess: () => {
queryClient.invalidateQueries(['users', 'list']) // No longer returning the promise
},
})
}
// userMutations.js
const useCreateUserMutation = () => {
const queryClient = useQueryClient()
return useMutation(resetStudentsProgress, {
onSuccess: () => {
queryClient.invalidateQueries(['users', 'list']) // No longer returning the promise
},
})
}
But this has the problem that createUserMutation.isLoading no longer waits for re-fetching users. I debugged the promise returned by invalidateQueries and it is correctly resolving, so that's not the issue. However, the weirdest thing here is that changing mutate to mutateAsync() DOES work.
const onSubmit = (values) => createUserMutation.mutateAsync(values)
.then(() => window.alert('User created successfully')) // <- WORKS!!! But why?
const onSubmit = (values) => createUserMutation.mutateAsync(values)
.then(() => window.alert('User created successfully')) // <- WORKS!!! But why?
This proves invalidateQueries is not hanging. But not why mutate().onSuccess() fails. Help please?
3 Replies
xenial-black
xenial-black•3y ago
the callbacks on mutate are only invoked if the observer is still subscribed. They will not trigger if the component has unmounted: https://tkdodo.eu/blog/mastering-mutations-in-react-query#some-callbacks-might-not-fire
Mastering Mutations in React Query
Learn all about the concept of performing side effects on the server with React Query.
flat-fuchsia
flat-fuchsiaOP•3y ago
Thank you for the explanation @TkDodo 🔮 ! That makes sense. However, I know for a fact the component is not being unmounted because a) it's still visible and b) the callback to hide that UI component is processed by the onSuccess which is not running. I read your article and it seems that my components are indeed doing what's recommended (query invalidation logic on useMutation callbacks, toast notification + UI changes on mutate callbacks)
1) Do things that are absolutely necessary and logic related (like query invalidation) in the useMutation callbacks. 2) Do UI related things like redirects or showing toast notifications in mutate callbacks. If the user navigated away from the current screen before the mutation finished, those will purposefully not fire.
I'm afraid tihs doesn't explain why the mutate's onSuccess isn't working... Do you think it might be worth to create a more detailed post and raise this as as a bug on the Tanstack Query github? Something worth mentioning, is the only page this happens on on our site is on one with a few disabled queries. And those are being affected by invalidateQueries. And this bug report seems sort of similar to the issue we are having: https://github.com/TanStack/query/issues/3202
GitHub
Disabled queries (enabled: false) get affected by invalidateQueries...
Describe the bug queryClient.invalidateQueries(queryKey, { refetchInactive: true, }) also refetches disabled queries (enabled: false) but - #947 (comment) looks like this issue was introduce in thi...
xenial-black
xenial-black•3y ago
the mentioned issue is resolved afaik. if you can provide a codesandbox reproduction, I can take a closer look

Did you find this page helpful?