Saltar al contenido principal
Versión: 11.x

TanStack React Query

Traducción Beta No Oficial

Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →

Compared to our classic React Query Integration this client is simpler and more TanStack Query-native, providing factories for common TanStack React Query interfaces like QueryKeys, QueryOptions, and MutationOptions. We think it's the future and recommend using this over the classic client, read the announcement post for more information about this change.

Consulta rápida de ejemplo

tsx
import { useQuery } from '@tanstack/react-query';
import { useTRPC } from './trpc';
function Users() {
const trpc = useTRPC();
const greetingQuery = useQuery(trpc.greeting.queryOptions({ name: 'Jerry' }));
// greetingQuery.data === 'Hello Jerry'
}
tsx
import { useQuery } from '@tanstack/react-query';
import { useTRPC } from './trpc';
function Users() {
const trpc = useTRPC();
const greetingQuery = useQuery(trpc.greeting.queryOptions({ name: 'Jerry' }));
// greetingQuery.data === 'Hello Jerry'
}

Uso

La filosofía de este cliente es proporcionar fábricas ligeras y seguras en tipos que funcionan de forma nativa y segura con Tanstack React Query. Esto significa que simplemente siguiendo las sugerencias de autocompletado que ofrece el cliente, podrás concentrarte en desarrollar usando únicamente los conocimientos de la documentación de TanStack React Query.

tsx
export default function Basics() {
const trpc = useTRPC();
const queryClient = useQueryClient();
// Create QueryOptions which can be passed to query hooks
const myQueryOptions = trpc.path.to.query.queryOptions({ /** inputs */ })
const myQuery = useQuery(myQueryOptions)
// or:
// useSuspenseQuery(myQueryOptions)
// useInfiniteQuery(myQueryOptions)
// Create MutationOptions which can be passed to useMutation
const myMutationOptions = trpc.path.to.mutation.mutationOptions()
const myMutation = useMutation(myMutationOptions)
// Create a QueryKey which can be used to manipulated many methods
// on TanStack's QueryClient in a type-safe manner
const myQueryKey = trpc.path.to.query.queryKey()
const invalidateMyQueryKey = () => {
queryClient.invalidateQueries({ queryKey: myQueryKey })
}
return (
// Your app here
)
}
tsx
export default function Basics() {
const trpc = useTRPC();
const queryClient = useQueryClient();
// Create QueryOptions which can be passed to query hooks
const myQueryOptions = trpc.path.to.query.queryOptions({ /** inputs */ })
const myQuery = useQuery(myQueryOptions)
// or:
// useSuspenseQuery(myQueryOptions)
// useInfiniteQuery(myQueryOptions)
// Create MutationOptions which can be passed to useMutation
const myMutationOptions = trpc.path.to.mutation.mutationOptions()
const myMutation = useMutation(myMutationOptions)
// Create a QueryKey which can be used to manipulated many methods
// on TanStack's QueryClient in a type-safe manner
const myQueryKey = trpc.path.to.query.queryKey()
const invalidateMyQueryKey = () => {
queryClient.invalidateQueries({ queryKey: myQueryKey })
}
return (
// Your app here
)
}

El objeto trpc es completamente seguro en tipos y proporcionará autocompletado para todos los procedimientos en tu AppRouter. Al final del proxy, están disponibles los siguientes métodos:

queryOptions - consulta de datos

Disponible para todos los procedimientos de consulta. Proporciona un envoltorio seguro en tipos para la función queryOptions de Tanstack. El primer argumento es la entrada para el procedimiento, y el segundo acepta cualquier opción nativa de Tanstack React Query.

ts
const queryOptions = trpc.path.to.query.queryOptions(
{
/** input */
},
{
// Any Tanstack React Query options
staleTime: 1000,
},
);
ts
const queryOptions = trpc.path.to.query.queryOptions(
{
/** input */
},
{
// Any Tanstack React Query options
staleTime: 1000,
},
);

Adicionalmente, puedes proporcionar un objeto trpc a la función queryOptions para pasar opciones de solicitud tRPC al cliente.

ts
const queryOptions = trpc.path.to.query.queryOptions(
{
/** input */
},
{
trpc: {
// Provide tRPC request options to the client
context: {
// see https://trpc.io/docs/client/links#managing-context
},
},
},
);
ts
const queryOptions = trpc.path.to.query.queryOptions(
{
/** input */
},
{
trpc: {
// Provide tRPC request options to the client
context: {
// see https://trpc.io/docs/client/links#managing-context
},
},
},
);

Si deseas deshabilitar una consulta de manera segura en tipos, puedes usar skipToken:

ts
import { skipToken } from '@tanstack/react-query';
const query = useQuery(
trpc.user.details.queryOptions(
user?.id && project?.id
? {
userId: user.id,
projectId: project.id,
}
: skipToken,
{
staleTime: 1000,
},
),
);
ts
import { skipToken } from '@tanstack/react-query';
const query = useQuery(
trpc.user.details.queryOptions(
user?.id && project?.id
? {
userId: user.id,
projectId: project.id,
}
: skipToken,
{
staleTime: 1000,
},
),
);

El resultado puede pasarse a los hooks useQuery o useSuspenseQuery, o a métodos del cliente de consultas como fetchQuery, prefetchQuery, prefetchInfiniteQuery, invalidateQueries, etc.

infiniteQueryOptions - consulta de datos infinitos

Disponible para todos los procedimientos de consulta que reciben una entrada de cursor. Proporciona un envoltorio seguro en tipos para la función infiniteQueryOptions de Tanstack. El primer argumento es la entrada para el procedimiento, y el segundo acepta cualquier opción nativa de Tanstack React Query.

ts
const infiniteQueryOptions = trpc.path.to.query.infiniteQueryOptions(
{
/** input */
},
{
// Any Tanstack React Query options
getNextPageParam: (lastPage, pages) => lastPage.nextCursor,
},
);
ts
const infiniteQueryOptions = trpc.path.to.query.infiniteQueryOptions(
{
/** input */
},
{
// Any Tanstack React Query options
getNextPageParam: (lastPage, pages) => lastPage.nextCursor,
},
);

queryKey - obtención de la clave de consulta y operaciones en el cliente

Disponible para todos los procedimientos de consulta. Permite acceder a la clave de consulta de manera segura en tipos.

ts
const queryKey = trpc.path.to.query.queryKey();
ts
const queryKey = trpc.path.to.query.queryKey();

Como Tanstack React Query usa coincidencia aproximada para claves de consulta, también puedes crear una clave parcial para cualquier subruta que coincida con todas las consultas de un enrutador:

ts
const queryKey = trpc.router.pathKey();
ts
const queryKey = trpc.router.pathKey();

O incluso la ruta raíz para hacer coincidir todas las consultas tRPC:

ts
const queryKey = trpc.pathKey();
ts
const queryKey = trpc.pathKey();

infiniteQueryKey - obtención de la clave de consulta infinita

Disponible para todos los procedimientos de consulta que reciben una entrada de cursor. Permite acceder a la clave de consulta para consultas infinitas de manera segura en tipos.

ts
const infiniteQueryKey = trpc.path.to.query.infiniteQueryKey({
/** input */
});
ts
const infiniteQueryKey = trpc.path.to.query.infiniteQueryKey({
/** input */
});

El resultado puede usarse con métodos del cliente de consultas como getQueryData, setQueryData, invalidateQueries, etc.

ts
const queryClient = useQueryClient();
// Get cached data for an infinite query
const cachedData = queryClient.getQueryData(
trpc.path.to.query.infiniteQueryKey({ cursor: 0 }),
);
// Set cached data for an infinite query
queryClient.setQueryData(
trpc.path.to.query.infiniteQueryKey({ cursor: 0 }),
(data) => {
// Modify the data
return data;
},
);
ts
const queryClient = useQueryClient();
// Get cached data for an infinite query
const cachedData = queryClient.getQueryData(
trpc.path.to.query.infiniteQueryKey({ cursor: 0 }),
);
// Set cached data for an infinite query
queryClient.setQueryData(
trpc.path.to.query.infiniteQueryKey({ cursor: 0 }),
(data) => {
// Modify the data
return data;
},
);

queryFilter - creación de filtros de consulta

Disponible para todos los procedimientos de consulta. Permite crear filtros de consulta de manera segura en tipos.

ts
const queryFilter = trpc.path.to.query.queryFilter(
{
/** input */
},
{
// Any Tanstack React Query filter
predicate: (query) => {
query.state.data;
},
},
);
ts
const queryFilter = trpc.path.to.query.queryFilter(
{
/** input */
},
{
// Any Tanstack React Query filter
predicate: (query) => {
query.state.data;
},
},
);

Al igual que con las claves de consulta, si deseas aplicar un filtro en todo un enrutador, puedes usar pathFilter para apuntar a cualquier subruta.

ts
const queryFilter = trpc.path.pathFilter({
// Any Tanstack React Query filter
predicate: (query) => {
query.state.data;
},
});
ts
const queryFilter = trpc.path.pathFilter({
// Any Tanstack React Query filter
predicate: (query) => {
query.state.data;
},
});

Útil para crear filtros que pueden pasarse a métodos del cliente como queryClient.invalidateQueries etc.

infiniteQueryFilter - creación de filtros para consultas infinitas

Disponible para todos los procedimientos de consulta que reciben una entrada de cursor. Permite crear filtros de consulta para consultas infinitas de manera segura en tipos.

ts
const infiniteQueryFilter = trpc.path.to.query.infiniteQueryFilter(
{
/** input */
},
{
// Any Tanstack React Query filter
predicate: (query) => {
query.state.data;
},
},
);
ts
const infiniteQueryFilter = trpc.path.to.query.infiniteQueryFilter(
{
/** input */
},
{
// Any Tanstack React Query filter
predicate: (query) => {
query.state.data;
},
},
);

Útil para crear filtros que pueden pasarse a métodos del cliente como queryClient.invalidateQueries etc.

ts
await queryClient.invalidateQueries(
trpc.path.to.query.infiniteQueryFilter(
{},
{
predicate: (query) => {
// Filter logic based on query state
return query.state.data?.pages.length > 0;
},
},
),
);
ts
await queryClient.invalidateQueries(
trpc.path.to.query.infiniteQueryFilter(
{},
{
predicate: (query) => {
// Filter logic based on query state
return query.state.data?.pages.length > 0;
},
},
),
);

mutationOptions - creación de opciones de mutación

Disponible para todos los procedimientos de mutación. Proporciona una función de identificación segura en tipos para construir opciones que pueden pasarse a useMutation.

ts
const mutationOptions = trpc.path.to.mutation.mutationOptions({
// Any Tanstack React Query options
onSuccess: (data) => {
// do something with the data
},
});
ts
const mutationOptions = trpc.path.to.mutation.mutationOptions({
// Any Tanstack React Query options
onSuccess: (data) => {
// do something with the data
},
});

mutationKey - obtención de la clave de mutación

Disponible para todos los procedimientos de mutación. Permite obtener la clave de mutación de manera segura en tipos.

ts
const mutationKey = trpc.path.to.mutation.mutationKey();
ts
const mutationKey = trpc.path.to.mutation.mutationKey();

subscriptionOptions - creación de opciones de suscripción

TanStack no proporciona un hook de suscripción, por lo que mantenemos nuestra propia abstracción que funciona con una configuración estándar de suscripción tRPC. Disponible para todos los procedimientos de suscripción. Proporciona una función de identificación segura en tipos para construir opciones que pueden pasarse a useSubscription. Ten en cuenta que necesitas tener configurado en tu cliente tRPC el httpSubscriptionLink o el wsLink para usar suscripciones.

tsx
function SubscriptionExample() {
const trpc = useTRPC();
const subscription = useSubscription(
trpc.path.to.subscription.subscriptionOptions(
{
/** input */
},
{
enabled: true,
onStarted: () => {
// do something when the subscription is started
},
onData: (data) => {
// you can handle the data here
},
onError: (error) => {
// you can handle the error here
},
onConnectionStateChange: (state) => {
// you can handle the connection state here
},
},
),
);
// Or you can handle the state here
subscription.data; // The lastly received data
subscription.error; // The lastly received error
/**
* The current status of the subscription.
* Will be one of: `'idle'`, `'connecting'`, `'pending'`, or `'error'`.
*
* - `idle`: subscription is disabled or ended
* - `connecting`: trying to establish a connection
* - `pending`: connected to the server, receiving data
* - `error`: an error occurred and the subscription is stopped
*/
subscription.status;
// Reset the subscription (if you have an error etc)
subscription.reset();
return <>{/* ... */}</>;
}
tsx
function SubscriptionExample() {
const trpc = useTRPC();
const subscription = useSubscription(
trpc.path.to.subscription.subscriptionOptions(
{
/** input */
},
{
enabled: true,
onStarted: () => {
// do something when the subscription is started
},
onData: (data) => {
// you can handle the data here
},
onError: (error) => {
// you can handle the error here
},
onConnectionStateChange: (state) => {
// you can handle the connection state here
},
},
),
);
// Or you can handle the state here
subscription.data; // The lastly received data
subscription.error; // The lastly received error
/**
* The current status of the subscription.
* Will be one of: `'idle'`, `'connecting'`, `'pending'`, or `'error'`.
*
* - `idle`: subscription is disabled or ended
* - `connecting`: trying to establish a connection
* - `pending`: connected to the server, receiving data
* - `error`: an error occurred and the subscription is stopped
*/
subscription.status;
// Reset the subscription (if you have an error etc)
subscription.reset();
return <>{/* ... */}</>;
}

Prefijado de claves de consulta

Cuando usas múltiples proveedores de tRPC en una sola aplicación (ej. conectando a diferentes servicios backend), las consultas con la misma ruta colisionarán en la caché. Puedes evitar esto habilitando el prefijado de claves de consulta.

tsx
// Without prefixes - these would collide!
const authQuery = useQuery(trpcAuth.list.queryOptions()); // auth service
const billingQuery = useQuery(trpcBilling.list.queryOptions()); // billing service
tsx
// Without prefixes - these would collide!
const authQuery = useQuery(trpcAuth.list.queryOptions()); // auth service
const billingQuery = useQuery(trpcBilling.list.queryOptions()); // billing service

Habilita la bandera de función al crear tu contexto:

utils/trpc.ts
tsx
// [...]
const billing = createTRPCContext<BillingRouter, { keyPrefix: true }>();
export const BillingProvider = billing.TRPCProvider;
export const useBilling = billing.useTRPC;
export const createBillingClient = () =>
createTRPCClient<BillingRouter>({
links: [
/* ... */
],
});
const account = createTRPCContext<AccountRouter, { keyPrefix: true }>();
export const AccountProvider = account.TRPCProvider;
export const useAccount = account.useTRPC;
export const createAccountClient = () =>
createTRPCClient<AccountRouter>({
links: [
/* ... */
],
});
utils/trpc.ts
tsx
// [...]
const billing = createTRPCContext<BillingRouter, { keyPrefix: true }>();
export const BillingProvider = billing.TRPCProvider;
export const useBilling = billing.useTRPC;
export const createBillingClient = () =>
createTRPCClient<BillingRouter>({
links: [
/* ... */
],
});
const account = createTRPCContext<AccountRouter, { keyPrefix: true }>();
export const AccountProvider = account.TRPCProvider;
export const useAccount = account.useTRPC;
export const createAccountClient = () =>
createTRPCClient<AccountRouter>({
links: [
/* ... */
],
});
App.tsx
tsx
// [...]
export function App() {
const [queryClient] = useState(() => new QueryClient());
const [billingClient] = useState(() => createBillingClient());
const [accountClient] = useState(() => createAccountClient());
return (
<QueryClientProvider client={queryClient}>
<BillingProvider
trpcClient={billingClient}
queryClient={queryClient}
keyPrefix="billing"
>
<AccountProvider
trpcClient={accountClient}
queryClient={queryClient}
keyPrefix="account"
>
{/* ... */}
</AccountProvider>
</BillingProvider>
</QueryClientProvider>
);
}
App.tsx
tsx
// [...]
export function App() {
const [queryClient] = useState(() => new QueryClient());
const [billingClient] = useState(() => createBillingClient());
const [accountClient] = useState(() => createAccountClient());
return (
<QueryClientProvider client={queryClient}>
<BillingProvider
trpcClient={billingClient}
queryClient={queryClient}
keyPrefix="billing"
>
<AccountProvider
trpcClient={accountClient}
queryClient={queryClient}
keyPrefix="account"
>
{/* ... */}
</AccountProvider>
</BillingProvider>
</QueryClientProvider>
);
}
components/MyComponent.tsx
tsx
// [...]
export function MyComponent() {
const billing = useBilling();
const account = useAccount();
const billingList = useQuery(billing.list.queryOptions());
const accountList = useQuery(account.list.queryOptions());
return (
<div>
<div>Billing: {JSON.stringify(billingList.data ?? null)}</div>
<div>Account: {JSON.stringify(accountList.data ?? null)}</div>
</div>
);
}
components/MyComponent.tsx
tsx
// [...]
export function MyComponent() {
const billing = useBilling();
const account = useAccount();
const billingList = useQuery(billing.list.queryOptions());
const accountList = useQuery(account.list.queryOptions());
return (
<div>
<div>Billing: {JSON.stringify(billingList.data ?? null)}</div>
<div>Account: {JSON.stringify(accountList.data ?? null)}</div>
</div>
);
}

Las claves de consulta se prefijarán correctamente para evitar colisiones:

tsx
// Example of how the query keys look with prefixes
const queryKeys = [
[['billing'], ['list'], { type: 'query' }],
[['account'], ['list'], { type: 'query' }],
];
tsx
// Example of how the query keys look with prefixes
const queryKeys = [
[['billing'], ['list'], { type: 'query' }],
[['account'], ['list'], { type: 'query' }],
];

Inferencia de tipos de entrada y salida

Cuando necesitas inferir los tipos de entrada y salida para un procedimiento o enrutador, hay 2 opciones disponibles según la situación.

Inferir tipos de entrada y salida de un enrutador completo

ts
import type { inferRouterInputs, inferRouterOutputs } from '@trpc/server';
import { AppRouter } from './path/to/server';
export type Inputs = inferRouterInputs<AppRouter>;
export type Outputs = inferRouterOutputs<AppRouter>;
ts
import type { inferRouterInputs, inferRouterOutputs } from '@trpc/server';
import { AppRouter } from './path/to/server';
export type Inputs = inferRouterInputs<AppRouter>;
export type Outputs = inferRouterOutputs<AppRouter>;

Inferir tipos para un procedimiento individual

ts
import type { inferInput, inferOutput } from '@trpc/tanstack-react-query';
function Component() {
const trpc = useTRPC();
type Input = inferInput<typeof trpc.path.to.procedure>;
type Output = inferOutput<typeof trpc.path.to.procedure>;
}
ts
import type { inferInput, inferOutput } from '@trpc/tanstack-react-query';
function Component() {
const trpc = useTRPC();
type Input = inferInput<typeof trpc.path.to.procedure>;
type Output = inferOutput<typeof trpc.path.to.procedure>;
}

Acceso al cliente tRPC

Si usaste la configuración con React Context, puedes acceder al cliente tRPC usando el hook useTRPCClient.

tsx
import { useTRPCClient } from './trpc';
function Component() {
const trpcClient = useTRPCClient();
const result = await trpcClient.path.to.procedure.query({
/** input */
});
}
tsx
import { useTRPCClient } from './trpc';
function Component() {
const trpcClient = useTRPCClient();
const result = await trpcClient.path.to.procedure.query({
/** input */
});
}

Si configuraste sin React Context, puedes importar directamente la instancia global del cliente en su lugar.

ts
import { client } from './trpc';
const result = await client.path.to.procedure.query({
/** input */
});
ts
import { client } from './trpc';
const result = await client.path.to.procedure.query({
/** input */
});