T
tRPC

❓-help

onSuccess invalidate

AGAlex Gomes11/30/2023
I'm trying to follow along with Theo's T3 tutorial using the latest Next version and the app router. The "setInput("")" and the invalidation don't seem to be working inside of onSuccess, the console.log is being called, what am I missing? Is this supposed to work?
"use client";

import { useUser } from "@clerk/nextjs";
import Image from "next/image";
import { Loader } from "./loader";
import { api } from "~/trpc/react";
import { useState } from "react";

export function CreatePost() {
const { user } = useUser();
const utils = api.useUtils();
const [input, setInput] = useState<string>("");
const { mutate, isLoading } = api.post.create.useMutation({
onSuccess: () => {
console.log("THIS IS BEING LOGGED");
// INPUT IS NO BEING RESET
setInput("");
// PAGE IS NOT SHOWING FRESH DATA
void utils.post.getAll.invalidate();
},
});

const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
mutate({ content: input });
};

if (!user) return <Loader />;

return (
<div className="flex flex-1 items-center gap-3">
<form onSubmit={handleSubmit} className="flex grow">
<input
onChange={(e) => setInput(e.target.value)}
placeholder="Start typing something..."
type="text"
disabled={isLoading}
/>
<button
type="submit"
disabled={isLoading}
>
{isLoading ? <Loader size={18} /> : "Post"}
</button>
</form>
</div>
);
}
"use client";

import { useUser } from "@clerk/nextjs";
import Image from "next/image";
import { Loader } from "./loader";
import { api } from "~/trpc/react";
import { useState } from "react";

export function CreatePost() {
const { user } = useUser();
const utils = api.useUtils();
const [input, setInput] = useState<string>("");
const { mutate, isLoading } = api.post.create.useMutation({
onSuccess: () => {
console.log("THIS IS BEING LOGGED");
// INPUT IS NO BEING RESET
setInput("");
// PAGE IS NOT SHOWING FRESH DATA
void utils.post.getAll.invalidate();
},
});

const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
mutate({ content: input });
};

if (!user) return <Loader />;

return (
<div className="flex flex-1 items-center gap-3">
<form onSubmit={handleSubmit} className="flex grow">
<input
onChange={(e) => setInput(e.target.value)}
placeholder="Start typing something..."
type="text"
disabled={isLoading}
/>
<button
type="submit"
disabled={isLoading}
>
{isLoading ? <Loader size={18} /> : "Post"}
</button>
</form>
</div>
);
}
dependencies:
"dependencies": {
"@clerk/nextjs": "^4.27.2",
"@prisma/client": "^5.6.0",
"@t3-oss/env-nextjs": "^0.7.1",
"@tanstack/react-query": "^4.36.1",
"@trpc/client": "^10.43.6",
"@trpc/next": "^10.43.6",
"@trpc/react-query": "^10.43.6",
"@trpc/server": "^10.43.6",
"date-fns": "^2.30.0",
"next": "^14.0.3",
"react": "18.2.0",
"react-dom": "18.2.0",
"server-only": "^0.0.1",
"superjson": "^2.2.1",
"zod": "^3.22.4"
},
"dependencies": {
"@clerk/nextjs": "^4.27.2",
"@prisma/client": "^5.6.0",
"@t3-oss/env-nextjs": "^0.7.1",
"@tanstack/react-query": "^4.36.1",
"@trpc/client": "^10.43.6",
"@trpc/next": "^10.43.6",
"@trpc/react-query": "^10.43.6",
"@trpc/server": "^10.43.6",
"date-fns": "^2.30.0",
"next": "^14.0.3",
"react": "18.2.0",
"react-dom": "18.2.0",
"server-only": "^0.0.1",
"superjson": "^2.2.1",
"zod": "^3.22.4"
},
KKrishna12/1/2023
in the input component you are not setting the value property. you need
<input
value={input}
...
/>
<input
value={input}
...
/>
AGAlex Gomes12/1/2023
Ahhh yeah this explains why the input wasn't being cleared, but my posts aren't updated, I need to manually refresh the page for my new post to appear
KKrishna12/1/2023
what posts? will need more context...
AGAlex Gomes12/1/2023
The CreatePost component creates a post when you submit the form:
const { mutate, isLoading } = api.post.create.useMutation({
onSuccess: () => {
console.log("THIS IS BEING LOGGED");
// INPUT IS NO BEING RESET
setInput("");
// PAGE IS NOT SHOWING FRESH DATA
void utils.post.getAll.invalidate();
},
});

const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
mutate({ content: input });
};
const { mutate, isLoading } = api.post.create.useMutation({
onSuccess: () => {
console.log("THIS IS BEING LOGGED");
// INPUT IS NO BEING RESET
setInput("");
// PAGE IS NOT SHOWING FRESH DATA
void utils.post.getAll.invalidate();
},
});

const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
mutate({ content: input });
};
export const postRouter = createTRPCRouter({
create: privateProcedure
.input(z.object({ content: z.string().min(1).max(255) }))
.mutation(async ({ ctx, input }) => {
const authorId = ctx.user.id;

const { success } = await rateLimit.limit(authorId);
if (!success) throw new TRPCError({ code: "TOO_MANY_REQUESTS" });

const post = await ctx.db.post.create({
data: { authorId, content: input.content },
select: { authorId: true, content: true, id: true },
});
return post;
}),
getAll: publicProcedure.query(async ({ ctx }) => {
const posts = await ctx.db.post.findMany({
take: 100,
orderBy: { createdAt: "desc" },
});
const users = (
await clerkClient.users.getUserList({
userId: posts.map((post) => post.authorId),
limit: 100,
})
).map(filterUserForClient);
return posts.map((post) => {
const author = users.find((user) => user.id === post.authorId);
if (!author)
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "Author not found",
});
return {
post,
author,
};
});
}),
});
export const postRouter = createTRPCRouter({
create: privateProcedure
.input(z.object({ content: z.string().min(1).max(255) }))
.mutation(async ({ ctx, input }) => {
const authorId = ctx.user.id;

const { success } = await rateLimit.limit(authorId);
if (!success) throw new TRPCError({ code: "TOO_MANY_REQUESTS" });

const post = await ctx.db.post.create({
data: { authorId, content: input.content },
select: { authorId: true, content: true, id: true },
});
return post;
}),
getAll: publicProcedure.query(async ({ ctx }) => {
const posts = await ctx.db.post.findMany({
take: 100,
orderBy: { createdAt: "desc" },
});
const users = (
await clerkClient.users.getUserList({
userId: posts.map((post) => post.authorId),
limit: 100,
})
).map(filterUserForClient);
return posts.map((post) => {
const author = users.find((user) => user.id === post.authorId);
if (!author)
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "Author not found",
});
return {
post,
author,
};
});
}),
});
then onSuccess in useMutation calls the invalidate on post.getAll which I assume should cause the getAll to fetch fresh posts
import { api } from "~/trpc/server";
import PostView from "../_components/post-view";

export default async function Home() {
const allPosts = await api.post.getAll.query();
return (
<main className="text-white">
<ul className="flex flex-col gap-2 divide-y divide-slate-700">
{allPosts.map((post) => (
<PostView postWithAuthor={post} key={post.post.id} />
))}
</ul>
</main>
);
}
import { api } from "~/trpc/server";
import PostView from "../_components/post-view";

export default async function Home() {
const allPosts = await api.post.getAll.query();
return (
<main className="text-white">
<ul className="flex flex-col gap-2 divide-y divide-slate-700">
{allPosts.map((post) => (
<PostView postWithAuthor={post} key={post.post.id} />
))}
</ul>
</main>
);
}
KKrishna12/1/2023
I dont know how invalidate works... but Im pretty sure the assumption is flawed... you can use useQuery & call the refetch property within it on update of posts... better would be to use query-keys within usequery which would trigger a fresh refetch automatically
Jjunior112/2/2023
How to set trpc on next js 14, im lost in the documentsion Please help me

Looking for more? Join the community!

Recommended Posts
React Query client and caller client under one objectWould love to know if it is possible to have caller and react query clients under one object? I feeI want to refetch and set the inital data of an useStateHello guys, currently i am retrieving the data i use in useState with `SSR`, but i want to use someVanilla Client Error HandlingWhat is the right way to handle errors when using the vanilla client? If I setup a client like so: sidebar searchPlease how will I implement a search on the left sidebar to let the items on the search bar be searcWS with TRPC```ts │  Type '({ req, res, }: { req: Request; res: Response; }) => CreateInnerContextOpts' is tRPC is butchering object types in return typesSo if I have a mutation that returns this type ```ts { name?: string } ``` the type that tRPC infersWhy my Authorization does not update ?i have this in `_app.tsx` ```export default function App({ Component, pageProps }: AppProps) { retTypeError: queryClient.getMutationDefaults is not a function (it is undefined)Hi! There's not much code to show here, as I'm really not sure where the error actually occurs. InuseQuery never returning or hitting APII have something off in my configuration, i copied most of the files from the `❯ npm create t3-app@lType 'QueryClient' is missing the following properties from type 'QueryClient': queryCache, mutationI am trying to setup a new project and doing my first client side query and getting this error: ```trpc mutation call stuckI have an issue with a simple mutation procedure: `getPublicUser: publicProcedure .input(z.objeCreate client based on OpenAPIHi! I am running a golang server with an openapi spec and would love to use trpc client in my fronteTRPC with react query, getting error twice?When i am try to show TRPC error in the client side with react-query, i am getting error twice from Error building create-t3-app: Page couldn't be rendered statically because it used `cookies`I get the following error when building create-t3-app: ``` TRPCClientError: Dynamic server usage: PaCompressing parts of query/mutation inputHi, I'm using trpc with the proxyclient for typesafety but recently hit an obstacle where some strin`useSuspenseQuery` still runs a fetch on SSR even when setting `ssr: false` in the api configBeside double-fetching, this causes issues during rendering if you have auth on your routes as the SUnsubscription callback triggering immediatelyHey! I am currently using Bun that's queried via a Vue application. For some reason the unsubscribeMultiple optimistic updates and old data from refetchesHi all, I'm new to tRPC and React Query and I'm just trying to get my head around what exactly I'm dPass headers when prefetching using helpersI dont see a way to pass headers and cookies with either fetch/prefetch methods from the ssr helper.I am getting a errors after starting a TRPC project with T3. "Unsafe return of an `any` typed value"It seems like something is off between Prisma and TRPC but I can't figure out why the type infrence