Mnigos
Mnigos
TtRPC
Created by Mnigos on 5/28/2025 in #❓-help
How to setup trpc with react router 7?
I'm especially interested in prefetching queries with trpc. I used this tutorial, but here He created caller instead of prefetching queries and then hydrating them. https://dev.to/ayoubphy/step-by-step-guide-setting-up-trpc-better-auth-prisma-and-react-router-v7-4ho My current setup. app/server/trpc.ts
import superjson from 'superjson'

import { initTRPC } from '@trpc/server'
import { ZodError } from 'zod'

import { prisma } from '~/server/prisma'

export function createTRPCContext() {
return {
prisma,
}
}
type Context = Awaited<ReturnType<typeof createTRPCContext>>

const t = initTRPC.context<Context>().create({
transformer: superjson,
errorFormatter: ({ shape, error }) => ({
...shape,
data: {
...shape.data,
zodError: error.cause instanceof ZodError ? error.cause.flatten() : null,
},
}),
})

export const createCallerFactory = t.createCallerFactory
export const createTRPCRouter = t.router
export const publicProcedure = t.procedure
import superjson from 'superjson'

import { initTRPC } from '@trpc/server'
import { ZodError } from 'zod'

import { prisma } from '~/server/prisma'

export function createTRPCContext() {
return {
prisma,
}
}
type Context = Awaited<ReturnType<typeof createTRPCContext>>

const t = initTRPC.context<Context>().create({
transformer: superjson,
errorFormatter: ({ shape, error }) => ({
...shape,
data: {
...shape.data,
zodError: error.cause instanceof ZodError ? error.cause.flatten() : null,
},
}),
})

export const createCallerFactory = t.createCallerFactory
export const createTRPCRouter = t.router
export const publicProcedure = t.procedure
/app/lib/trpc/react.tsx
import SuperJSON from 'superjson'

import {
QueryClient,
QueryClientProvider,
defaultShouldDehydrateQuery,
} from '@tanstack/react-query'
import { createTRPCClient, httpBatchLink, loggerLink } from '@trpc/client'
import { createTRPCContext } from '@trpc/tanstack-react-query'
import { cache, useState } from 'react'

import type { inferRouterInputs, inferRouterOutputs } from '@trpc/server'
import { clientEnv } from '~/env.client'
import type { AppRouter } from '~/server/main'

function makeQueryClient() {
return new QueryClient({
defaultOptions: {
queries: {
staleTime: 60 * 1000,
},
dehydrate: {
serializeData: SuperJSON.serialize,
shouldDehydrateQuery: query =>
defaultShouldDehydrateQuery(query) ||
query.state.status === 'pending',
},
hydrate: {
deserializeData: SuperJSON.deserialize,
},
},
})
}

let browserQueryClient: QueryClient | undefined = undefined

export const getQueryClient = cache(() => {
if (typeof window === 'undefined') return makeQueryClient()

browserQueryClient ??= makeQueryClient()

return browserQueryClient
})

const getBaseUrl = cache(() => {
if (typeof window !== 'undefined') return window.location.origin

if (clientEnv?.VITE_VERCEL_URL) return `https://${clientEnv.VITE_VERCEL_URL}`

return 'http://localhost:5173'
})

const links = [
loggerLink({
enabled: op =>
process.env.NODE_ENV === 'development' ||
(op.direction === 'down' && op.result instanceof Error),
}),
httpBatchLink({
transformer: SuperJSON,
url: `${getBaseUrl()}/api/trpc`,
headers() {
const headers = new Headers()
headers.set('x-trpc-source', 'react')
return headers
},
}),
]

export const { TRPCProvider, useTRPC } = createTRPCContext<AppRouter>()

export function TRPCReactProvider({ children }: { children: React.ReactNode }) {
const queryClient = getQueryClient()
const [trpcClient] = useState(() =>
createTRPCClient<AppRouter>({
links,
}),
)

return (
<QueryClientProvider client={queryClient}>
<TRPCProvider trpcClient={trpcClient} queryClient={queryClient}>
{children}
</TRPCProvider>
</QueryClientProvider>
)
}

export type RouterInputs = inferRouterInputs<AppRouter>
export type RouterOutputs = inferRouterOutputs<AppRouter>
import SuperJSON from 'superjson'

import {
QueryClient,
QueryClientProvider,
defaultShouldDehydrateQuery,
} from '@tanstack/react-query'
import { createTRPCClient, httpBatchLink, loggerLink } from '@trpc/client'
import { createTRPCContext } from '@trpc/tanstack-react-query'
import { cache, useState } from 'react'

import type { inferRouterInputs, inferRouterOutputs } from '@trpc/server'
import { clientEnv } from '~/env.client'
import type { AppRouter } from '~/server/main'

function makeQueryClient() {
return new QueryClient({
defaultOptions: {
queries: {
staleTime: 60 * 1000,
},
dehydrate: {
serializeData: SuperJSON.serialize,
shouldDehydrateQuery: query =>
defaultShouldDehydrateQuery(query) ||
query.state.status === 'pending',
},
hydrate: {
deserializeData: SuperJSON.deserialize,
},
},
})
}

let browserQueryClient: QueryClient | undefined = undefined

export const getQueryClient = cache(() => {
if (typeof window === 'undefined') return makeQueryClient()

browserQueryClient ??= makeQueryClient()

return browserQueryClient
})

const getBaseUrl = cache(() => {
if (typeof window !== 'undefined') return window.location.origin

if (clientEnv?.VITE_VERCEL_URL) return `https://${clientEnv.VITE_VERCEL_URL}`

return 'http://localhost:5173'
})

const links = [
loggerLink({
enabled: op =>
process.env.NODE_ENV === 'development' ||
(op.direction === 'down' && op.result instanceof Error),
}),
httpBatchLink({
transformer: SuperJSON,
url: `${getBaseUrl()}/api/trpc`,
headers() {
const headers = new Headers()
headers.set('x-trpc-source', 'react')
return headers
},
}),
]

export const { TRPCProvider, useTRPC } = createTRPCContext<AppRouter>()

export function TRPCReactProvider({ children }: { children: React.ReactNode }) {
const queryClient = getQueryClient()
const [trpcClient] = useState(() =>
createTRPCClient<AppRouter>({
links,
}),
)

return (
<QueryClientProvider client={queryClient}>
<TRPCProvider trpcClient={trpcClient} queryClient={queryClient}>
{children}
</TRPCProvider>
</QueryClientProvider>
)
}

export type RouterInputs = inferRouterInputs<AppRouter>
export type RouterOutputs = inferRouterOutputs<AppRouter>
4 replies
TtRPC
Created by Mnigos on 9/29/2024 in #❓-help
How to use client and react-query simultaneously?
I'm using this with nextjs app router and i want to have access to both query and useQuery methods.
4 replies