How to refetch data for a query when a mutation is performed in a different component?

I’ve been looking through the docs on tRPC and React Query but can’t quite figure this out. To give a quick explanation of what I’m trying to do, I’m creating a system where a user can request to join a group and then the admins can accept or decline the request. Component A is fetching the request status on the user side through a useQuery on one of my tRPC procedures. Component B performs a mutation (accept or decline) on the admin side from one of my tRPC procedures and I want it to immediately update the request status that the user sees in Component A after the admin accepts or declines. I’ve tried messing with refetchQueries() and invalidateQueries() in the onSuccess of the mutation but have had no luck.
9 Replies
Ramsay
Ramsay11mo ago
Invalidating the query in the onSuccess should just work. Maybe share some code.
WO
WO11mo ago
Gotcha here's the code Component A (checking request status on user side)
const {
data: joinRequestStatus,
isLoading: isLoadingJoinRequestStatus,
refetch: refetchJoinRequestStatus,
} = api.leagueUserManagement.getJoinRequestStatus.useQuery(
{
leagueSlug: league.leagueSlug,
},

{
queryKey: [
"leagueUserManagement.getJoinRequestStatus",
{ leagueSlug: league.leagueSlug },
],
staleTime: 5 * (60 * 1000),
cacheTime: 10 * (60 * 1000),
}
);
const {
data: joinRequestStatus,
isLoading: isLoadingJoinRequestStatus,
refetch: refetchJoinRequestStatus,
} = api.leagueUserManagement.getJoinRequestStatus.useQuery(
{
leagueSlug: league.leagueSlug,
},

{
queryKey: [
"leagueUserManagement.getJoinRequestStatus",
{ leagueSlug: league.leagueSlug },
],
staleTime: 5 * (60 * 1000),
cacheTime: 10 * (60 * 1000),
}
);
Component B (declining the user request on admin side)
import { QueryClient } from "@tanstack/react-query";
const queryClient = new QueryClient();
const { mutate: declineJoinRequest, isLoading: isLoadingDeclineJoinRequest } =
api.leagueUserManagement.declineJoinRequest.useMutation({
onSuccess: async () => {
toast({
title: "Success",
description: "Join request declined",
variant: "success",
});
await refetchJoinRequests();
await queryClient.invalidateQueries({
queryKey: [
"leagueUserManagement.getJoinRequestStatus",
{ leagueSlug: leagueSlug },
],
});
},
onError: (error) => {
toast({
title: "Error",
description: error.message,
variant: "error",
});
},
});
import { QueryClient } from "@tanstack/react-query";
const queryClient = new QueryClient();
const { mutate: declineJoinRequest, isLoading: isLoadingDeclineJoinRequest } =
api.leagueUserManagement.declineJoinRequest.useMutation({
onSuccess: async () => {
toast({
title: "Success",
description: "Join request declined",
variant: "success",
});
await refetchJoinRequests();
await queryClient.invalidateQueries({
queryKey: [
"leagueUserManagement.getJoinRequestStatus",
{ leagueSlug: leagueSlug },
],
});
},
onError: (error) => {
toast({
title: "Error",
description: error.message,
variant: "error",
});
},
});
I think im doing something wrong with the queryKey field because Im not seeing any intelisense for it. In the docs its not very clear how to set the queryKey
Ramsay
Ramsay11mo ago
You're creating a new queryClient and invalidating the query in this empty client that is never being used. trpc gives you a query invalidation helper https://trpc.io/docs/client/react/useContext#query-invalidation
useContext | tRPC
useContext is a hook that gives you access to helpers that let you manage the cached data of the queries you execute via @trpc/react-query. These helpers are actually thin wrappers around @tanstack/react-query's queryClient methods. If you want more in-depth information about options and usage patterns for useContext helpers than what we provide...
Ramsay
Ramsay11mo ago
You also don't need to use query keys with trpc https://trpc.io/docs/client/react#differences-to-vanilla-react-query
React Query Integration | tRPC
React Query Integration
WO
WO11mo ago
Gotcha, thanks thats good to know. I updated my code to use the useContext from tRPC but the I'm still not getting the fresh data on the user side.
import { api } from "~/utils/api";

const utils = api.useContext();

const { mutate: declineJoinRequest, isLoading: isLoadingDeclineJoinRequest } =
api.leagueUserManagement.declineJoinRequest.useMutation({
onSuccess: async () => {
toast({
title: "Success",
description: "Join request declined",
variant: "success",
});
await refetchJoinRequests();
await utils.leagueUserManagement.getJoinRequestStatus.invalidate();
},
onError: (error) => {
toast({
title: "Error",
description: error.message,
variant: "error",
});
},
});
import { api } from "~/utils/api";

const utils = api.useContext();

const { mutate: declineJoinRequest, isLoading: isLoadingDeclineJoinRequest } =
api.leagueUserManagement.declineJoinRequest.useMutation({
onSuccess: async () => {
toast({
title: "Success",
description: "Join request declined",
variant: "success",
});
await refetchJoinRequests();
await utils.leagueUserManagement.getJoinRequestStatus.invalidate();
},
onError: (error) => {
toast({
title: "Error",
description: error.message,
variant: "error",
});
},
});
Is this the correct setup? I also removed the query key from the query on the user side
Ramsay
Ramsay11mo ago
try utils.leagueUserManagement.getJoinRequestStatus.invalidate({ leagueSlug })
WO
WO11mo ago
Just tried that but doesnt seem to be working. Not seeing anything in the console indicating that its refetching the new status either Could it be some conflict with the cacheTime field in the query?
Ramsay
Ramsay11mo ago
I don't think so, query invalidation should just mark the query as stale, maybe just try to remove them though to see if anything changes. Also maybe try removing the async await from onSuccess and removing the refetchJoinRequests function since I'm assuming that's doing what you're trying to do with invalidate. If that doesn't work verify that the value of leagueSlug you're passing to invalidate is the same value you're passing to useQuery.
WO
WO11mo ago
Tried all of those and no luck. Very strange. Think ill just have to live with it not working