Skip to content

Commit 701d4e0

Browse files
committed
feat: use tRPC's new tanstack react query integration instead of the classic integration
1 parent 47abf94 commit 701d4e0

File tree

5 files changed

+66
-28
lines changed

5 files changed

+66
-28
lines changed

cli/src/installers/dependencyVersionMap.ts

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export const dependencyVersionMap = {
3030
"@trpc/client": "^11.0.0",
3131
"@trpc/server": "^11.0.0",
3232
"@trpc/react-query": "^11.0.0",
33+
"@trpc/tanstack-react-query": "^11.1.2",
3334
"@trpc/next": "^11.0.0",
3435
"@tanstack/react-query": "^5.69.0",
3536
superjson: "^2.2.1",

cli/src/installers/trpc.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ export const trpcInstaller: Installer = ({
1717
"superjson",
1818
"@trpc/server",
1919
"@trpc/client",
20-
"@trpc/react-query",
20+
"@trpc/react-query", // The legacy integration package is necessary for `createHydrationHelpers`. We can remove it once https://github.com/vercel/next.js/discussions/60640 is resolved.
21+
"@trpc/tanstack-react-query",
2122
],
2223
devMode: false,
2324
});

cli/template/extras/src/app/_components/post-tw.tsx

+20-9
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,31 @@
11
"use client";
22

3+
import {
4+
useMutation,
5+
useQueryClient,
6+
useSuspenseQuery,
7+
} from "@tanstack/react-query";
38
import { useState } from "react";
49

5-
import { api } from "~/trpc/react";
10+
import { useTRPC } from "~/trpc/react";
611

712
export function LatestPost() {
8-
const [latestPost] = api.post.getLatest.useSuspenseQuery();
13+
const trpc = useTRPC();
14+
const queryClient = useQueryClient();
15+
16+
const { data: latestPost } = useSuspenseQuery(
17+
trpc.post.getLatest.queryOptions()
18+
);
919

10-
const utils = api.useUtils();
1120
const [name, setName] = useState("");
12-
const createPost = api.post.create.useMutation({
13-
onSuccess: async () => {
14-
await utils.post.invalidate();
15-
setName("");
16-
},
17-
});
21+
const createPost = useMutation(
22+
trpc.post.create.mutationOptions({
23+
onSuccess: async () => {
24+
await queryClient.invalidateQueries({ queryKey: trpc.post.pathKey() });
25+
setName("");
26+
},
27+
})
28+
);
1829

1930
return (
2031
<div className="w-full max-w-xs">

cli/template/extras/src/app/_components/post.tsx

+20-9
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,32 @@
11
"use client";
22

3+
import {
4+
useMutation,
5+
useQueryClient,
6+
useSuspenseQuery,
7+
} from "@tanstack/react-query";
38
import { useState } from "react";
49

5-
import { api } from "~/trpc/react";
10+
import { useTRPC } from "~/trpc/react";
611
import styles from "../index.module.css";
712

813
export function LatestPost() {
9-
const [latestPost] = api.post.getLatest.useSuspenseQuery();
14+
const trpc = useTRPC();
15+
const queryClient = useQueryClient();
16+
17+
const { data: latestPost } = useSuspenseQuery(
18+
trpc.post.getLatest.queryOptions()
19+
);
1020

11-
const utils = api.useUtils();
1221
const [name, setName] = useState("");
13-
const createPost = api.post.create.useMutation({
14-
onSuccess: async () => {
15-
await utils.post.invalidate();
16-
setName("");
17-
},
18-
});
22+
const createPost = useMutation(
23+
trpc.post.create.mutationOptions({
24+
onSuccess: async () => {
25+
await queryClient.invalidateQueries({ queryKey: trpc.post.pathKey() });
26+
setName("");
27+
},
28+
})
29+
);
1930

2031
return (
2132
<div className={styles.showcaseContainer}>

cli/template/extras/src/trpc/react.tsx

+23-9
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
"use client";
22

3-
import { QueryClientProvider, type QueryClient } from "@tanstack/react-query";
4-
import { httpBatchStreamLink, loggerLink } from "@trpc/client";
5-
import { createTRPCReact } from "@trpc/react-query";
3+
import {
4+
isServer,
5+
QueryClientProvider,
6+
type QueryClient,
7+
} from "@tanstack/react-query";
8+
import {
9+
createTRPCClient,
10+
httpBatchStreamLink,
11+
loggerLink,
12+
} from "@trpc/client";
613
import { type inferRouterInputs, type inferRouterOutputs } from "@trpc/server";
14+
import { createTRPCContext } from "@trpc/tanstack-react-query";
715
import { useState } from "react";
816
import SuperJSON from "superjson";
917

@@ -12,17 +20,23 @@ import { createQueryClient } from "./query-client";
1220

1321
let clientQueryClientSingleton: QueryClient | undefined = undefined;
1422
const getQueryClient = () => {
15-
if (typeof window === "undefined") {
23+
if (isServer) {
1624
// Server: always make a new query client
1725
return createQueryClient();
1826
}
19-
// Browser: use singleton pattern to keep the same query client
27+
// Browser: make a new query client if we don't already have one
28+
// This is very important, so we don't re-make a new client if React
29+
// suspends during the initial render. This may not be needed if we
30+
// have a suspense boundary BELOW the creation of the query client
2031
clientQueryClientSingleton ??= createQueryClient();
2132

2233
return clientQueryClientSingleton;
2334
};
2435

25-
export const api = createTRPCReact<AppRouter>();
36+
const api = createTRPCContext<AppRouter>();
37+
38+
export const useTRPC = api.useTRPC;
39+
export const useTRPCClient = api.useTRPCClient;
2640

2741
/**
2842
* Inference helper for inputs.
@@ -42,7 +56,7 @@ export function TRPCReactProvider(props: { children: React.ReactNode }) {
4256
const queryClient = getQueryClient();
4357

4458
const [trpcClient] = useState(() =>
45-
api.createClient({
59+
createTRPCClient<AppRouter>({
4660
links: [
4761
loggerLink({
4862
enabled: (op) =>
@@ -64,9 +78,9 @@ export function TRPCReactProvider(props: { children: React.ReactNode }) {
6478

6579
return (
6680
<QueryClientProvider client={queryClient}>
67-
<api.Provider client={trpcClient} queryClient={queryClient}>
81+
<api.TRPCProvider trpcClient={trpcClient} queryClient={queryClient}>
6882
{props.children}
69-
</api.Provider>
83+
</api.TRPCProvider>
7084
</QueryClientProvider>
7185
);
7286
}

0 commit comments

Comments
 (0)