Set up the React Query Integration
How to use and setup tRPC in React
On this page
1. Install dependencies
The following dependencies should be installed.
pnpm add @trpc/server @trpc/client @trpc/react-query @tanstack/react-querynpm install @trpc/server @trpc/client @trpc/react-query @tanstack/react-queryyarn add @trpc/server @trpc/client @trpc/react-query @tanstack/react-querybun add @trpc/server @trpc/client @trpc/react-query @tanstack/react-query2. Import your AppRouter
Import your AppRouter type into the client application. This type holds the shape of your entire API.
utils/trpc.ts
import type { type AppRouter = Router<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{
post: BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{
byId: QueryProcedure<{
input: {
id: string;
};
output: {
id: string;
title: string;
};
meta: object;
errorShape: DefaultErrorShape;
}>;
}>>;
}>> & DecorateCreateRouterOptions<{
post: BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{
byId: QueryProcedure<{
input: {
id: string;
};
output: {
id: string;
title: string;
};
meta: object;
errorShape: DefaultErrorShape;
}>;
}>>;
}>
AppRouter } from '../server/router';3. Create tRPC hooks
Create a set of strongly-typed React hooks from your AppRouter type signature with createTRPCReact.
utils/trpc.ts
import { function createTRPCReact<TRouter extends AnyRouter, TSSRContext = unknown>(opts?: CreateTRPCReactOptions<TRouter>): CreateTRPCReact<TRouter, TSSRContext>createTRPCReact } from '@trpc/react-query';
import type { type AppRouter = Router<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{
getUser: QueryProcedure<{
input: {
id: string;
};
output: {
name: string;
};
meta: object;
errorShape: DefaultErrorShape;
}>;
createUser: MutationProcedure<{
input: {
name: string;
};
output: string;
meta: object;
errorShape: DefaultErrorShape;
}>;
}>> & DecorateCreateRouterOptions<{
getUser: QueryProcedure<{
input: {
id: string;
};
output: {
name: string;
};
meta: object;
errorShape: DefaultErrorShape;
}>;
createUser: MutationProcedure<{
input: {
name: string;
};
output: string;
meta: object;
errorShape: DefaultErrorShape;
}>;
}>
AppRouter } from '../server/router';
export const const trpc: CreateTRPCReactBase<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{
getUser: QueryProcedure<{
input: {
id: string;
};
output: {
name: string;
};
meta: object;
errorShape: DefaultErrorShape;
}>;
createUser: MutationProcedure<{
input: {
name: string;
};
output: string;
meta: object;
errorShape: DefaultErrorShape;
}>;
}>>, unknown> & DecorateRouterRecord<...>
trpc = createTRPCReact<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{
getUser: QueryProcedure<{
input: {
id: string;
};
output: {
name: string;
};
meta: object;
errorShape: DefaultErrorShape;
}>;
createUser: MutationProcedure<{
input: {
name: string;
};
output: string;
meta: object;
errorShape: DefaultErrorShape;
}>;
}>>, unknown>(opts?: CreateTRPCReactOptions<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<...>>> | undefined): CreateTRPCReactBase<...> & DecorateRouterRecord<...>
createTRPCReact<type AppRouter = Router<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{
getUser: QueryProcedure<{
input: {
id: string;
};
output: {
name: string;
};
meta: object;
errorShape: DefaultErrorShape;
}>;
createUser: MutationProcedure<{
input: {
name: string;
};
output: string;
meta: object;
errorShape: DefaultErrorShape;
}>;
}>> & DecorateCreateRouterOptions<{
getUser: QueryProcedure<{
input: {
id: string;
};
output: {
name: string;
};
meta: object;
errorShape: DefaultErrorShape;
}>;
createUser: MutationProcedure<{
input: {
name: string;
};
output: string;
meta: object;
errorShape: DefaultErrorShape;
}>;
}>
AppRouter>();4. Add tRPC providers
Create a tRPC client, and wrap your application in the tRPC Provider, as below. You will also need to set up and connect React Query, which they document in more depth.
App.tsx
import { class QueryClientQueryClient, const QueryClientProvider: ({ client, children }: QueryClientProviderProps) => React.JSX.ElementQueryClientProvider } from '@tanstack/react-query';
import { function httpBatchLink<TRouter extends AnyRouter>(opts: HTTPBatchLinkOptions<TRouter["_def"]["_config"]["$types"]>): TRPCLink<TRouter>httpBatchLink } from '@trpc/client';
import React, { function useState<S>(initialState: S | (() => S)): [S, React.Dispatch<React.SetStateAction<S>>] (+1 overload)useState } from 'react';
import { const trpc: CreateTRPCReactBase<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{
getUser: QueryProcedure<{
input: {
id: string;
};
output: {
name: string;
};
meta: object;
errorShape: DefaultErrorShape;
}>;
createUser: MutationProcedure<{
input: {
name: string;
};
output: string;
meta: object;
errorShape: DefaultErrorShape;
}>;
}>>, unknown> & DecorateRouterRecord<...>
trpc } from './utils/trpc';
export function function App(): React.JSX.ElementApp() {
const [const queryClient: QueryClientqueryClient] = useState<QueryClient>(initialState: QueryClient | (() => QueryClient)): [QueryClient, React.Dispatch<React.SetStateAction<QueryClient>>] (+1 overload)useState(() => new new QueryClient(config?: QueryClientConfig): QueryClientQueryClient());
const [const trpcClient: TRPCClient<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{
getUser: QueryProcedure<{
input: {
id: string;
};
output: {
name: string;
};
meta: object;
errorShape: DefaultErrorShape;
}>;
createUser: MutationProcedure<{
input: {
name: string;
};
output: string;
meta: object;
errorShape: DefaultErrorShape;
}>;
}>>>
trpcClient] = useState<TRPCClient<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{
getUser: QueryProcedure<{
input: {
id: string;
};
output: {
name: string;
};
meta: object;
errorShape: DefaultErrorShape;
}>;
createUser: MutationProcedure<{
input: {
name: string;
};
output: string;
meta: object;
errorShape: DefaultErrorShape;
}>;
}>>>>(initialState: TRPCClient<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<...>>> | (() => TRPCClient<...>)): [...] (+1 overload)
useState(() =>
const trpc: CreateTRPCReactBase<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{
getUser: QueryProcedure<{
input: {
id: string;
};
output: {
name: string;
};
meta: object;
errorShape: DefaultErrorShape;
}>;
createUser: MutationProcedure<{
input: {
name: string;
};
output: string;
meta: object;
errorShape: DefaultErrorShape;
}>;
}>>, unknown> & DecorateRouterRecord<...>
trpc.createClient: (opts: CreateTRPCClientOptions<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{
getUser: QueryProcedure<{
input: {
id: string;
};
output: {
name: string;
};
meta: object;
errorShape: DefaultErrorShape;
}>;
createUser: MutationProcedure<{
input: {
name: string;
};
output: string;
meta: object;
errorShape: DefaultErrorShape;
}>;
}>>>) => TRPCClient<...>
createClient({
links: TRPCLink<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{
getUser: QueryProcedure<{
input: {
id: string;
};
output: {
name: string;
};
meta: object;
errorShape: DefaultErrorShape;
}>;
createUser: MutationProcedure<{
input: {
name: string;
};
output: string;
meta: object;
errorShape: DefaultErrorShape;
}>;
}>>>[]
links: [
httpBatchLink<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{
getUser: QueryProcedure<{
input: {
id: string;
};
output: {
name: string;
};
meta: object;
errorShape: DefaultErrorShape;
}>;
createUser: MutationProcedure<{
input: {
name: string;
};
output: string;
meta: object;
errorShape: DefaultErrorShape;
}>;
}>>>(opts: HTTPBatchLinkOptions<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}>): TRPCLink<...>
httpBatchLink({
url: string | URLurl: 'http://localhost:3000/trpc',
// You can pass any HTTP headers you wish here
async headers?: HTTPHeaders | ((opts: {
opList: NonEmptyArray<Operation>;
}) => HTTPHeaders | Promise<HTTPHeaders>) | undefined
headers() {
return {
authorization: stringauthorization: function getAuthCookie(): stringgetAuthCookie(),
};
},
}),
],
}),
);
return (
<const trpc: CreateTRPCReactBase<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{
getUser: QueryProcedure<{
input: {
id: string;
};
output: {
name: string;
};
meta: object;
errorShape: DefaultErrorShape;
}>;
createUser: MutationProcedure<{
input: {
name: string;
};
output: string;
meta: object;
errorShape: DefaultErrorShape;
}>;
}>>, unknown> & DecorateRouterRecord<...>
trpc.type Provider: TRPCProvider<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{
getUser: QueryProcedure<{
input: {
id: string;
};
output: {
name: string;
};
meta: object;
errorShape: DefaultErrorShape;
}>;
createUser: MutationProcedure<{
input: {
name: string;
};
output: string;
meta: object;
errorShape: DefaultErrorShape;
}>;
}>>, unknown>
Provider TRPCProviderProps<BuiltRouter<{ ctx: object; meta: object; errorShape: DefaultErrorShape; transformer: false; }, DecorateCreateRouterOptions<{ getUser: QueryProcedure<{ input: { id: string; }; output: { name: string; }; meta: object; errorShape: DefaultErrorShape; }>; createUser: MutationProcedure<...>; }>>, unknown>.client: TRPCClient<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{
getUser: QueryProcedure<{
input: {
id: string;
};
output: {
name: string;
};
meta: object;
errorShape: DefaultErrorShape;
}>;
createUser: MutationProcedure<{
input: {
name: string;
};
output: string;
meta: object;
errorShape: DefaultErrorShape;
}>;
}>>> | TRPCUntypedClient<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<...>>>
client={const trpcClient: TRPCClient<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{
getUser: QueryProcedure<{
input: {
id: string;
};
output: {
name: string;
};
meta: object;
errorShape: DefaultErrorShape;
}>;
createUser: MutationProcedure<{
input: {
name: string;
};
output: string;
meta: object;
errorShape: DefaultErrorShape;
}>;
}>>>
trpcClient} queryClient: QueryClientqueryClient={const queryClient: QueryClientqueryClient}>
<const QueryClientProvider: ({ client, children }: QueryClientProviderProps) => React.JSX.ElementQueryClientProvider client: QueryClientclient={const queryClient: QueryClientqueryClient}>
{/* Your app here */}
</const QueryClientProvider: ({ client, children }: QueryClientProviderProps) => React.JSX.ElementQueryClientProvider>
</const trpc: CreateTRPCReactBase<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{
getUser: QueryProcedure<{
input: {
id: string;
};
output: {
name: string;
};
meta: object;
errorShape: DefaultErrorShape;
}>;
createUser: MutationProcedure<{
input: {
name: string;
};
output: string;
meta: object;
errorShape: DefaultErrorShape;
}>;
}>>, unknown> & DecorateRouterRecord<...>
trpc.type Provider: TRPCProvider<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{
getUser: QueryProcedure<{
input: {
id: string;
};
output: {
name: string;
};
meta: object;
errorShape: DefaultErrorShape;
}>;
createUser: MutationProcedure<{
input: {
name: string;
};
output: string;
meta: object;
errorShape: DefaultErrorShape;
}>;
}>>, unknown>
Provider>
);
}5. Fetch data
You can now use the tRPC React Query integration to call queries and mutations on your API.
pages/IndexPage.tsx
import { const trpc: CreateTRPCReactBase<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{
getUser: QueryProcedure<{
input: {
id: string;
};
output: {
name: string;
};
meta: object;
errorShape: DefaultErrorShape;
}>;
createUser: MutationProcedure<{
input: {
name: string;
};
output: string;
meta: object;
errorShape: DefaultErrorShape;
}>;
}>>, unknown> & DecorateRouterRecord<...>
trpc } from '../utils/trpc';
export default function function IndexPage(): React.JSX.ElementIndexPage() {
const const userQuery: UseTRPCQueryResult<{
name: string;
}, TRPCClientErrorLike<{
input: {
id: string;
};
output: {
name: string;
};
transformer: false;
errorShape: DefaultErrorShape;
}>>
userQuery = const trpc: CreateTRPCReactBase<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{
getUser: QueryProcedure<{
input: {
id: string;
};
output: {
name: string;
};
meta: object;
errorShape: DefaultErrorShape;
}>;
createUser: MutationProcedure<{
input: {
name: string;
};
output: string;
meta: object;
errorShape: DefaultErrorShape;
}>;
}>>, unknown> & DecorateRouterRecord<...>
trpc.getUser: DecoratedQuery<{
input: {
id: string;
};
output: {
name: string;
};
transformer: false;
errorShape: DefaultErrorShape;
}>
getUser.useQuery: ProcedureUseQuery
<{
name: string;
}, {
name: string;
}>(input: {
id: string;
} | unique symbol, opts?: UseTRPCQueryOptions<{
name: string;
}, {
name: string;
}, TRPCClientErrorLike<{
input: {
id: string;
};
output: {
name: string;
};
transformer: false;
errorShape: DefaultErrorShape;
}>, {
name: string;
}> | undefined) => UseTRPCQueryResult<{
name: string;
}, TRPCClientErrorLike<{
input: {
id: string;
};
output: {
name: string;
};
transformer: false;
errorShape: DefaultErrorShape;
}>> (+1 overload)
useQuery({ id: stringid: 'id_bilbo' });
const const userCreator: UseTRPCMutationResult<string, TRPCClientErrorLike<{
input: {
name: string;
};
output: string;
transformer: false;
errorShape: DefaultErrorShape;
}>, {
name: string;
}, unknown>
userCreator = const trpc: CreateTRPCReactBase<BuiltRouter<{
ctx: object;
meta: object;
errorShape: DefaultErrorShape;
transformer: false;
}, DecorateCreateRouterOptions<{
getUser: QueryProcedure<{
input: {
id: string;
};
output: {
name: string;
};
meta: object;
errorShape: DefaultErrorShape;
}>;
createUser: MutationProcedure<{
input: {
name: string;
};
output: string;
meta: object;
errorShape: DefaultErrorShape;
}>;
}>>, unknown> & DecorateRouterRecord<...>
trpc.createUser: DecoratedMutation<{
input: {
name: string;
};
output: string;
transformer: false;
errorShape: DefaultErrorShape;
}>
createUser.useMutation: <unknown>(opts?: UseTRPCMutationOptions<{
name: string;
}, TRPCClientErrorLike<{
input: {
name: string;
};
output: string;
transformer: false;
errorShape: DefaultErrorShape;
}>, string, unknown> | undefined) => UseTRPCMutationResult<string, TRPCClientErrorLike<{
input: {
name: string;
};
output: string;
transformer: false;
errorShape: DefaultErrorShape;
}>, {
name: string;
}, unknown>
useMutation();
return (
<React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div>
<React.JSX.IntrinsicElements.p: React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>p>{const userQuery: UseTRPCQueryResult<{
name: string;
}, TRPCClientErrorLike<{
input: {
id: string;
};
output: {
name: string;
};
transformer: false;
errorShape: DefaultErrorShape;
}>>
userQuery.data: {
name: string;
} | undefined
data?.name: string | undefinedname}</React.JSX.IntrinsicElements.p: React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>p>
<React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>button React.DOMAttributes<HTMLButtonElement>.onClick?: React.MouseEventHandler<HTMLButtonElement> | undefinedonClick={() => const userCreator: UseTRPCMutationResult<string, TRPCClientErrorLike<{
input: {
name: string;
};
output: string;
transformer: false;
errorShape: DefaultErrorShape;
}>, {
name: string;
}, unknown>
userCreator.mutate: (variables: {
name: string;
}, options?: MutateOptions<string, TRPCClientErrorLike<{
input: {
name: string;
};
output: string;
transformer: false;
errorShape: DefaultErrorShape;
}>, {
name: string;
}, unknown> | undefined) => void
mutate({ name: stringname: 'Frodo' })}>
Create Frodo
</React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>button>
</React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div>
);
}