Last active
April 3, 2025 14:41
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"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