Skip to content

Instantly share code, notes, and snippets.

@jwoyo
Last active April 3, 2025 14:41
Show Gist options
  • Save jwoyo/ae62e8896bccf8e735e249dccc9b492e to your computer and use it in GitHub Desktop.
Save jwoyo/ae62e8896bccf8e735e249dccc9b492e to your computer and use it in GitHub Desktop.
create-t3-app: gradual adoption of new queryOptions and mutationOptions pattern in trpc and react-query
"use client";
import { QueryClientProvider, type QueryClient } from "@tanstack/react-query";
import { httpBatchStreamLink, loggerLink } from "@trpc/client";
import { createTRPCReact } from "@trpc/react-query";
import { type inferRouterInputs, type inferRouterOutputs } from "@trpc/server";
// see here ⬇️
import {
createTRPCOptionsProxy,
type TRPCOptionsProxy,
} from "@trpc/tanstack-react-query";
// ........ ⬆️
import { createContext, useContext, useState } from "react";
import SuperJSON from "superjson";
import { type AppRouter } from "~/server/api/root";
import { createQueryClient } from "./query-client";
let clientQueryClientSingleton: QueryClient | undefined = undefined;
const getQueryClient = () => {
if (typeof window === "undefined") {
// Server: always make a new query client
return createQueryClient();
}
// Browser: use singleton pattern to keep the same query client
clientQueryClientSingleton ??= createQueryClient();
return clientQueryClientSingleton;
};
export const api = createTRPCReact<AppRouter>();
/**
* Inference helper for inputs.
*
* @example type HelloInput = RouterInputs['example']['hello']
*/
export type RouterInputs = inferRouterInputs<AppRouter>;
/**
* Inference helper for outputs.
*
* @example type HelloOutput = RouterOutputs['example']['hello']
*/
export type RouterOutputs = inferRouterOutputs<AppRouter>;
export function TRPCReactProvider(props: { children: React.ReactNode }) {
const queryClient = getQueryClient();
const [trpcClient] = useState(() =>
api.createClient({
links: [
loggerLink({
enabled: (op) =>
process.env.NODE_ENV === "development" ||
(op.direction === "down" && op.result instanceof Error),
}),
httpBatchStreamLink({
transformer: SuperJSON,
url: getBaseUrl() + "/api/trpc",
headers: () => {
const headers = new Headers();
headers.set("x-trpc-source", "nextjs-react");
return headers;
},
}),
],
}),
);
// see here ⬇️
const [optionsProxy] = useState(() =>
createTRPCOptionsProxy<AppRouter>({ client: trpcClient, queryClient }),
);
// ........ ⬆️
return (
<QueryClientProvider client={queryClient}>
<api.Provider
client={trpcClient}
queryClient={queryClient}
>
// see here ⬇️
<TrpcInteropContext.Provider
value={{
optionsProxy,
}}
>
{props.children}
</TrpcInteropContext.Provider>
// ........ ⬆️
</api.Provider>
</QueryClientProvider>
);
}
const TrpcInteropContext = createContext<{
optionsProxy: TRPCOptionsProxy<AppRouter>;
}>(null!);
// see here ⬇️
// use this hook like outlined here: https://trpc.io/docs/client/tanstack-react-query/usage
export const useTRPC = () => {
const { optionsProxy } = useContext(TrpcInteropContext);
return optionsProxy;
};
// ........ ⬆️
function getBaseUrl() {
if (typeof window !== "undefined") return window.location.origin;
if (process.env.VERCEL_URL) return `https://${process.env.VERCEL_URL}`;
return `http://localhost:${process.env.PORT ?? 3000}`;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment