React Query
Simplify React Query usage with minimal integration using ORPC and TanStack Query
Installation
npm install @orpc/client @orpc/react-query @tanstack/react-query
Setup
Using a Global Client
import { createORPCReactQueryUtils } from '@orpc/react-query';
import { createORPCClient } from '@orpc/client';
import { ORPCLink } from '@orpc/client/fetch';
import type { router } from 'examples/server';
const orpcLink = new ORPCLink({
url: 'http://localhost:3000/rpc',
// fetch: optional override for the default fetch function
// headers: provide additional headers
})
const client = createORPCClient<typeof router /* or contract router */>(orpcLink)
// Create React Query utilities for ORPC
export const orpc = createORPCReactQueryUtils(client);
orpc.getUser.- infiniteOptions
- key
- mutationOptions
- queryOptions
Using Context with a Client
import { createORPCReactQueryUtils, RouterUtils } from '@orpc/react-query';
import { createORPCClient } from '@orpc/client';
import { ORPCLink } from '@orpc/client/fetch';
import { RouterClient } from '@orpc/server';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import type { router } from 'examples/server';
import * as React from 'react';
const ORPCContext = React.createContext<RouterUtils<RouterClient<typeof router, unknown>> | undefined>(undefined);
export function useORPC() {
const orpc = React.useContext(ORPCContext);
if (!orpc) {
throw new Error('ORPCContext is not available.');
}
return orpc;
}
export function ORPCProvider({ children }: { children: React.ReactNode }) {
const [client] = React.useState(() => {
const orpcLink = new ORPCLink({
url: 'https://exanple.com/api',
// fetch: optional override for the default fetch function
// headers: provide additional headers
});
return createORPCClient<typeof router>(orpcLink);
});
const [queryClient] = React.useState(() => new QueryClient());
const orpc = React.useMemo(() => createORPCReactQueryUtils(client), [client]);
return (
<QueryClientProvider client={queryClient}>
<ORPCContext.Provider value={orpc}>
{children}
</ORPCContext.Provider>
</QueryClientProvider>
);
}
// Example usage
const orpc = useORPC();
orpc.getUser.- infiniteOptions
- key
- mutationOptions
- queryOptions
Multiple ORPC Instances
To prevent conflicts when using multiple ORPC instances, you can provide a unique base path to createORPCReactQueryUtils
.
import { createORPCReactQueryUtils } from '@orpc/react-query'
// Create separate ORPC instances with unique base paths
const userORPC = createORPCReactQueryUtils('fake-client' as any, ['__user-api__'])
const postORPC = createORPCReactQueryUtils('fake-client' as any, ['__post-api__'])
This ensures that each instance manages its own set of query keys and avoids any conflicts.
Usage
Standard Queries and Mutations
import { useMutation, useQuery, useQueryClient, useSuspenseQuery } from '@tanstack/react-query'
import { orpc } from 'examples/react-query'
// Fetch data
const { data: gettingData } = useQuery(orpc.getUser.queryOptions({ input: { id: '123' } }))
// Use suspense query
const { data: postData } = useSuspenseQuery(
orpc.posts.getPost.queryOptions({ input: { id: 'example' } }),
)
// Perform mutations
const { mutate: postMutate } = useMutation(orpc.posts.createPost.mutationOptions())
// Invalidate queries
const queryClient = useQueryClient()
queryClient.invalidateQueries({ queryKey: orpc.key() }) // Invalidate all queries
queryClient.invalidateQueries({ queryKey: orpc.posts.getPost.key({ input: { id: 'example' } }) }) // Specific queries
Note: This library enhances TanStack Query by managing query keys and functions for you, providing a seamless developer experience.
Infinite Queries
Infinite queries require a cursor
in the input field for pagination.
import { os, createRouterClient } from '@orpc/server';
import { z } from 'zod';
import { createORPCReactQueryUtils } from '@orpc/react-query';
import { useInfiniteQuery, useSuspenseInfiniteQuery } from '@tanstack/react-query';
import * as React from 'react';
const router = {
user: {
list: os
.input(z.object({ cursor: z.number(), limit: z.number() }))
.handler(({ input }) => ({
nextCursor: input.cursor + input.limit,
users: [], // Fetch your actual data here
})),
},
};
const client = createRouterClient(router); // or any kind of client
const orpc = createORPCReactQueryUtils(client);
export function MyComponent() {
const query = useInfiniteQuery(
orpc.user.list.infiniteOptions({
input: { limit: 10 },
getNextPageParam: (lastPage) => lastPage.nextCursor,
initialPageParam: 0,
})
);
const query2 = useSuspenseInfiniteQuery(
orpc.user.list.infiniteOptions({
input: { limit: 10 },
getNextPageParam: (lastPage) => lastPage.nextCursor,
initialPageParam: 0,
})
);
return (
<div>
{query.isLoading && 'Loading...'}
{query.isSuccess && <div>Data: {JSON.stringify(query.data)}</div>}
{query.isError && <div>Error: {query.error.message}</div>}
</div>
);
}