Aller au contenu principal
Version : 11.x

TanStack React Query

Traduction BĂȘta Non Officielle

Cette page a Ă©tĂ© traduite par PageTurner AI (bĂȘta). Non approuvĂ©e officiellement par le projet. Vous avez trouvĂ© une erreur ? Signaler un problĂšme →

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.

Exemple rapide de requĂȘte​

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'
}

Utilisation​

La philosophie de ce client est de fournir des factories minces et typées qui fonctionnent nativement et de maniÚre type-safe avec Tanstack React Query. Cela signifie qu'en suivant simplement les autocomplétions fournies par le client, vous pouvez vous concentrer sur le développement en vous appuyant uniquement sur les connaissances des docs 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
)
}

L'objet trpc est entiÚrement type-safe et fournira des autocomplétions pour toutes les procédures de votre AppRouter. En fin de chaßne de proxy, les méthodes suivantes sont disponibles :

queryOptions - interrogation de donnĂ©es​

Disponible pour toutes les procĂ©dures de requĂȘte. Fournit un wrapper type-safe autour de la fonction queryOptions de Tanstack. Le premier argument correspond Ă  l'entrĂ©e de la procĂ©dure, et le second accepte toutes les options natives 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,
},
);

Vous pouvez Ă©galement fournir un objet trpc Ă  la fonction queryOptions pour transmettre des options de requĂȘte tRPC au client.

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 vous souhaitez dĂ©sactiver une requĂȘte de maniĂšre type-safe, vous pouvez utiliser 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,
},
),
);

Le rĂ©sultat peut ĂȘtre passĂ© aux hooks useQuery ou useSuspenseQuery, ou aux mĂ©thodes du client de requĂȘte comme fetchQuery, prefetchQuery, prefetchInfiniteQuery, invalidateQueries, etc.

infiniteQueryOptions - interrogation de donnĂ©es infinies​

Disponible pour toutes les procĂ©dures de requĂȘte acceptant une entrĂ©e de curseur. Fournit un wrapper type-safe autour de la fonction infiniteQueryOptions de Tanstack. Le premier argument correspond Ă  l'entrĂ©e de la procĂ©dure, et le second accepte toutes les options natives 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 - obtention de la clĂ© de requĂȘte et opĂ©rations sur le client de requĂȘte​

Disponible pour toutes les procĂ©dures de requĂȘte. Permet d'accĂ©der Ă  la clĂ© de requĂȘte de maniĂšre type-safe.

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

Comme Tanstack React Query utilise un matching flou pour les clĂ©s de requĂȘte, vous pouvez Ă©galement crĂ©er une clĂ© de requĂȘte partielle pour tout sous-chemin afin de correspondre Ă  toutes les requĂȘtes d'un routeur :

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

Ou mĂȘme le chemin racine pour correspondre Ă  toutes les requĂȘtes tRPC :

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

infiniteQueryKey - obtention de la clĂ© de requĂȘte infinie​

Disponible pour toutes les procĂ©dures de requĂȘte acceptant une entrĂ©e de curseur. Permet d'accĂ©der Ă  la clĂ© de requĂȘte pour une requĂȘte infinie de maniĂšre type-safe.

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

Le rĂ©sultat peut ĂȘtre utilisĂ© avec des mĂ©thodes du client de requĂȘte telles que 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 - crĂ©ation de filtres de requĂȘte​

Disponible pour toutes les procĂ©dures de requĂȘte. Permet de crĂ©er des filtres de requĂȘte de maniĂšre type-safe.

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;
},
},
);

Comme pour les clĂ©s de requĂȘte, si vous souhaitez appliquer un filtre sur un routeur entier, vous pouvez utiliser pathFilter pour cibler n'importe quel sous-chemin.

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;
},
});

Utile pour crĂ©er des filtres pouvant ĂȘtre passĂ©s aux mĂ©thodes client comme queryClient.invalidateQueries, etc.

infiniteQueryFilter - crĂ©ation de filtres de requĂȘte infinie​

Disponible pour toutes les procĂ©dures de requĂȘte acceptant une entrĂ©e de curseur. Permet de crĂ©er des filtres de requĂȘte pour les requĂȘtes infinies de maniĂšre type-safe.

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;
},
},
);

Utile pour crĂ©er des filtres pouvant ĂȘtre passĂ©s aux mĂ©thodes client comme 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 - crĂ©ation d'options de mutation​

Disponible pour toutes les procĂ©dures de mutation. Fournit une fonction d'identification type-safe pour construire des options pouvant ĂȘtre passĂ©es Ă  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 - obtention de la clĂ© de mutation​

Disponible pour toutes les procédures de mutation. Permet d'obtenir la clé de mutation de maniÚre type-safe.

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

subscriptionOptions - crĂ©ation d'options d'abonnement​

TanStack ne fournit pas de hook d'abonnement, nous exposons donc ici notre propre abstraction qui fonctionne avec une configuration standard d'abonnement tRPC. Disponible pour toutes les procĂ©dures d'abonnement. Fournit une fonction d'identification type-safe pour construire des options pouvant ĂȘtre passĂ©es Ă  useSubscription. Notez que vous devez avoir configurĂ© soit le httpSubscriptionLink soit le wsLink dans votre client tRPC pour utiliser les abonnements.

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 <>{/* ... */}</>;
}

PrĂ©fixage des clĂ©s de requĂȘte​

Lorsque vous utilisez plusieurs clients tRPC dans une mĂȘme application (par ex. pour vous connecter Ă  diffĂ©rents services backend), les requĂȘtes ayant le mĂȘme chemin entreront en conflit dans le cache. Vous pouvez Ă©viter cela en activant le prĂ©fixage des clĂ©s de requĂȘte.

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

Activez le feature flag lors de la création de votre contexte :

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>
);
}

Les clĂ©s de requĂȘte seront correctement prĂ©fixĂ©es pour Ă©viter les collisions :

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' }],
];

InfĂ©rer les types d'entrĂ©e et de sortie​

Lorsque vous devez inférer les types d'entrée et de sortie pour une procédure ou un routeur, deux options sont disponibles selon la situation.

Inférer les types d'entrée et de sortie d'un routeur complet

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>;

Inférer les types pour une procédure individuelle

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>;
}

AccĂ©der au client tRPC​

Si vous avez utilisé la configuration avec le contexte React, vous pouvez accéder au client tRPC via le 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 vous avez configuré sans contexte React, vous pouvez importer directement l'instance client globale.

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 */
});