Query Invalidation with trpc not working with React Server Components and App Router

Hi guys, I am trying to do Optimistic updates with trpc but the problem is I am fetching data on the server component using trpc and passing it to client component
const Dashboard = async () => {
noStore();
const session = await getServerAuthSession();

if (!session) {
redirect("/");
}

const dbWallets = await api.wallet.getAll();

return (
const Dashboard = async () => {
noStore();
const session = await getServerAuthSession();

if (!session) {
redirect("/");
}

const dbWallets = await api.wallet.getAll();

return (
and here is the revalidation code
const { mutate, isPending } = api.wallet.create.useMutation({
onSuccess: () => {
toast("Wallet has been created");
void utils.wallet.getAll.invalidate();
setIsOpen(false);
//revalidatePath("/dashboard");
},
});
const { mutate, isPending } = api.wallet.create.useMutation({
onSuccess: () => {
toast("Wallet has been created");
void utils.wallet.getAll.invalidate();
setIsOpen(false);
//revalidatePath("/dashboard");
},
});
Here I've tried with revalidatePath but that also does nothing Please help!!
A
aditya16d ago
I have deployed the application if anyone wants to try and see whats happening github: https://github.com/aditya-exe/money-mogul deployed: https://money-mogul.vercel.app
GitHub
GitHub - aditya-exe/money-mogul: A expense tracker for me
A expense tracker for me. Contribute to aditya-exe/money-mogul development by creating an account on GitHub.
Money Mogul
Created by a1000
M
Max16d ago
I think cache invalidation from the client side doesn't automatically trigger a re-invocation of the call from the server side. Observers are created via useQuery so on the server, you have none. So if you'd expect invalidateQueries to refetch the queries, this wouldn't happen. Possible Solutions I found, haven’t done this myself yet.
- refetch instead of invalidate? - I dont think it’s that simple tho - revalidatePath - This is what you want I think - https://nextjs.org/docs/app/api-reference/functions/revalidatePath - router.refresh() - I think this would also work - https://nextjs.org/docs/app/building-your-application/caching#routerrefresh let me know if any of those work or if you find a better solution. I'm seeing router.refresh() used more. You might be better off just using using suspense. "use client" components are deceptive as they do still run on the server. If you wrap it with a suspense you'll have a faster intial paint with your layout then it will stream in your component that relies on data when the data is available. So then you would be able to just invalidate it like you're trying to. U would just need to call const dbWallets = await api.wallet.getAll(); using the client api and wrap it with a suspense. https://www.joshwcomeau.com/react/server-components/ https://nextjs.org/docs/app/building-your-application/rendering/server-components
A
aditya15d ago
hi @Max thanks for useful info, right now router.refresh() is working like expected i guess "revalidatePath only invalidates the cache when the included path is next visited. This means calling revalidatePath with a dynamic route segment will not immediately trigger many revalidations at once. The invalidation only happens when the path is next visited." this is why revalidatePath is not working i will try doing this too but for now router works thanks!!
M
Max15d ago
Awesome good to know!
J
james1628612d ago
I was running into a similar issue and I found the solution. I have a server component that listed dialogues, and then part of that listing was a client component called DeleteDialogue that I used to delete the dialogues on click. I wanted the dialogue listing cache to invalidate when i deleted a dialogue- really just refetch the new list of entities. I think that invalidating the cache does not work because the listing page is a server component. Therefore, I needed to pass down a callback from the listing page to the client DeleteButton so that it revalidates the path. In DialoguesList.tsx (server comp)
const handleDeleteCallback = async () => {
"use server";
revalidatePath("/dialogues");
};
...

<DeleteDialogue
handleDeleteCallback={handleDeleteCallback}
id={d.id}
/>
const handleDeleteCallback = async () => {
"use server";
revalidatePath("/dialogues");
};
...

<DeleteDialogue
handleDeleteCallback={handleDeleteCallback}
id={d.id}
/>
In DeleteDialogues.tsx
const deleteDialogue = api.dialogue.delete.useMutation({
onSuccess: () => {
// Refresh the list of dialogues
console.log("Deleted dialogue");
handleDeleteCallback();
},
});
const deleteDialogue = api.dialogue.delete.useMutation({
onSuccess: () => {
// Refresh the list of dialogues
console.log("Deleted dialogue");
handleDeleteCallback();
},
});
I think you need to pass down a callback from the server component to the client component that will revalidate the path as explained here https://discord.com/channels/966627436387266600/1224762014010970252/1229995324463124490
C
Circusyesterday
@james162861 this process would only work for a child component existing on the same url path, right? Is there a way to handle this revalidation for non-child components and/or different paths?
J
james162861yesterday
@Circus 1) Different Paths: Let's say you are on /settings and want to delete a dialogue that is listed on /dialogues. When you make that deletion and then navigate to /dialogues, the data will be refetched and the dialogue will no longer show so i dont think you need to use revalidatePath. This is only useful when you have a everything in the same view- same path. 2) Parent components: The above example was <SeverComp><ClientComponent/></ServerComponent>, where the server is listing the dialogues and the client is deleting. If the structure was reversed, <ClientComponent><ServerComponent/></ClientComponent>, you would have lift the funciton up into the parent Client component. I dont this is a good idea.
C
Circusyesterday
I can confirm #2, but #1 does not work in TRPC, which is the issue I've encountered. The queries in server components seem to be cached in a way that navigating back to a page that has already been rendered will hold onto the old data until you refresh the page.
J
james162861yesterday
I just tested it out locally and it worked for me. It's gotta work. Are you using the same tab?
C
Circusyesterday
@james162861 Edited for clarification: I have attached a minimum repo link showing what I mean with a simple readme using T3's set up post router to show the issue. No packages added, using T3 stack @latest and minimal changes https://github.com/spenserschwartz/t3-trpc-revalidate-issue
Want results from more Discord servers?
Add your server
More Posts
Tanstack Virtual or Other optionsHey everyone, quick question for you all. I've been tasked with building a complex grid with horizoRevalidatepath type undefined vs pageHello! Does anyone know if there's supposed to be a difference between calling revalidatePath with Turborepo without Expo?Is there a way to get things working in a Turborepo without the expo app? I'm assuming the Expo appExtending next-auth userI'm trying to extend the next-auth user but somehow It's not returning new fields, and I only have tAre cold starts an issue?I haven't used Next API routes as a primary API before, and from what I understand they are mostly sI have a doubt .I have a doubt . suppose i am using a hosting platform which offers some free but limited resources Expo Router headerSearchBarOptionsHi folks, struggling quite a bit to try and implement the native iOS search bar in the header of a tIm a newbie creating a document editor and idk how to setup an architecture to save the dataI'm using tip tap for the editor on the front end while using Postgresql with bun on the back end. IDifferences Between ProvidersI'm in a small team and we are looking for some cloud providers to have the following things: - Servhow to use yarnrc.ymlI found this ``` nodeLinker: node-modules plugins: - path: .yarn/plugins/@yarnpkg/plugin-workspacA guide for tRPC MySQL drizzle testing setupHey folks I have built a product using t3 stack with MySQL db and drizzle as the ORM. I would like tshadcn/ui: Why do I get the incorrect error message?If I don't type anything in I only get the "required" message despite defining a message in the zod TRPCClientError: Unable to transform response from serverI just migrated from Next Auth to Clerk. Clerk is working fine. tRPC works fine too, but I keep gettBasic system design questions for a big projectHey, I am making a fairly ambitious app and wanted some advice on how to proceed with my system desiValidation error in JSON schema provided by user against the JSON Schema draft 2020-12?I have integrated monaco editor on my website and I want users to input JSON data and validate it agHow to change refType in forwardRef based on prop?imagine you want a React component to have a certain ref type if some prop is present, and another rHow do I migrate from Next-Auth to Clerk Auth?I recently started a project with with all options enabled with create T3 stack command, how do I miState ManagementI need help in managing state in nextjs, can someone help metable schema admins tableIs it better to have a table for admins a table for moderators and a tabble for users, or have just Prisma w/pgvectorHey, we got this t3 app, but Prisma does not support vectors when trying to query the column that's