3

I'm having an issue with React Query where if a user presses a button too fast, triggering a mutation, the correct value flashes and changes on the screen as the API calls are returned, even when attempting to cancel them. I notice this problem also happens in the official React Query example for optimistic updates. Here's a video I took of the problem happening there.

export const useIncreaseCount = () => {
    const queryClient = useQueryClient()

    return useMutation(
        () => {
            const cart = queryClient.getQueryData('cart') as Cart

            return setCart(cart)
        },
        {
            onMutate: async (cartItemId: string) => {
                await queryClient.cancelQueries('cart')

                const previousCart = queryClient.getQueryData('cart') as Cart

                queryClient.setQueryData(
                    'cart',
                    increaseCount(previousCart, cartItemId)
                )

                return { previousCart }
            },
            onError: (error, _cartItem, context) => {
                console.log('error mutating cart', error)
                if (!context) return
                queryClient.setQueryData('cart', context.previousCart)
            },
            onSuccess: () => {
                queryClient.invalidateQueries('cart')
            },
        }
    )
}

I'm thinking of debouncing the call to use useIncreaseCount, but then onMutate will get debounced, and I don't want that. Ideally just the API call would be debounced. Is there a built in way in React Query to do this?

0

1 Answer 1

5

The problem come from the fact that every onSuccess callback calls queryClient.invalidateQueries, even though a different invocation of the mutation is still running. It's the responsibility of the user code to not do that. I see two ways:

  • One thing we are doing sometimes is to track the amount of ongoing mutations with a ref (increment in onMutate, decrement in onSettled), then only call queryClient.invalidateQueries if the counter is zero.
  • assigning mutationKeys and using !queryClient.isMutating(key) should also work.
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks! Ending up going the ref route and it works perfectly. :). Also set ref to 0 if error
here is the implementation using ref (increment in onMutate, decrement in onSettled). Does not work most likely due to wrong imlementation. stackoverflow.com/questions/76000854/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.