I’m developing an online store using React. I have a functionality where, upon clicking a button, a product is added to favorites. After this action, I want to update the profile request (which returns user and favorites).
My code:
// useProfile.ts
import UserService from "@/services/user.service";
import { useQuery } from "@tanstack/react-query";
import { useUser } from "./useUser";
export const useProfile = () => {
const { user } = useUser();
const { data } = useQuery({
queryKey: ['profile'],
queryFn: () => {
return UserService.getProfile(user?.id || "");
},
select: ({ data }) => data
});
return {profile: data};
};
// LikeButton.tsx
import { useRef } from 'react';
import classes from './LikeButton.module.scss';
// @ts-ignore
import { ReactComponent as IconHeart } from '@/assets/img/svg/icon-heart.svg';
import { useProfile } from '@/hooks/useProfile';
import UserService from '@/services/user.service';
import { useMutation, useQueryClient } from '@tanstack/react-query';
interface ILikeButtonProps {
productId: number;
}
function LikeButton({ productId }: ILikeButtonProps) {
const { profile } = useProfile();
const { invalidateQueries } = useQueryClient();
const { mutate } = useMutation({
mutationKey: ['toggle favourite'],
mutationFn: () => UserService.toggleFavourite(productId),
onSuccess: () => {
console.log('onSuccess');
invalidateQueries({ queryKey: ['profile'] });
},
});
const btnRef = useRef<HTMLButtonElement>(null);
const buttonClasses = profile?.favourites.some((fp) => fp.id === productId)
? `${classes.btn_like} ${classes['btn_like--active']}`
: classes.btn_like;
return (
<button
ref={btnRef}
className={buttonClasses}
onClick={() => mutate()}
data-product-id={productId}
>
<IconHeart />
</button>
);
}
export default LikeButton;
However, for some reason, invalidateQueries doesn’t seem to work, or perhaps I’m doing something incorrectly… I couldn’t find an answer online 🙁
I added console.log – it works perfectly. But invalidateQueries isn’t being triggered.
2
Answers
The first issue was also that I wasn't returning anything from onSuccess.
Classic scenario: while waiting for an answer to my question, I found a solution myself. STRANGELY, the code snippet:
isn't working, but an almost identical one is working perfectly:
Maybe someone in the comments will explain how this works...
P.S. Tnx to this issue
As I’ve figured out in a reproduction you cannot destructure from
useQueryClient
hook. This means the functions (like invalidateQueries) need to be bound to the QueryClient when executed.This will work:
Destructuring DOES NOT work:
And to confirm, when reading the source code, the query client does indeed use
this
– https://github.com/TanStack/query/blob/ca6ad31c19c4d0dcfb8b95c462a575bc79c73bae/packages/query-core/src/queryClient.ts#L54.If you destructure the invalidateQueries method and then call it, it’s being called without a context, so it doesn’t know how to use
this
correctly – https://github.com/TanStack/query/blob/main/packages/query-core/src/queryClient.ts#L250-L269