TanStack React Query
빠른 예제 쿼리
tsximport {useQuery } from '@tanstack/react-query';import {useTRPC } from './trpc';functionUsers () {consttrpc =useTRPC ();constgreetingQuery =useQuery (trpc .greeting .queryOptions ({name : 'Jerry' }));// greetingQuery.data === 'Hello Jerry'}
tsximport {useQuery } from '@tanstack/react-query';import {useTRPC } from './trpc';functionUsers () {consttrpc =useTRPC ();constgreetingQuery =useQuery (trpc .greeting .queryOptions ({name : 'Jerry' }));// greetingQuery.data === 'Hello Jerry'}
사용법
이 클라이언트는 TanStack React Query의 사용 방식을 그대로 따르는 가볍고 타입 안전한 팩토리를 제공하는 것을 목표로 합니다. 자동완성을 따라 사용하면 TanStack React Query 문서의 지식을 그대로 활용하면서 개발에 집중할 수 있습니다.
tsxexport default functionBasics () {consttrpc =useTRPC ();constqueryClient =useQueryClient ();// Create QueryOptions which can be passed to query hooksconstmyQueryOptions =trpc .path .to .query .queryOptions ({ /** inputs */ })constmyQuery =useQuery (myQueryOptions )// or:// useSuspenseQuery(myQueryOptions)// useInfiniteQuery(myQueryOptions)// Create MutationOptions which can be passed to useMutationconstmyMutationOptions =trpc .path .to .mutation .mutationOptions ()constmyMutation =useMutation (myMutationOptions )// Create a QueryKey which can be used to manipulate many methods// on TanStack's QueryClient in a type-safe mannerconstmyQueryKey =trpc .path .to .query .queryKey ()constinvalidateMyQueryKey = () => {queryClient .invalidateQueries ({queryKey :myQueryKey })}return (// Your app herenull)}
tsxexport default functionBasics () {consttrpc =useTRPC ();constqueryClient =useQueryClient ();// Create QueryOptions which can be passed to query hooksconstmyQueryOptions =trpc .path .to .query .queryOptions ({ /** inputs */ })constmyQuery =useQuery (myQueryOptions )// or:// useSuspenseQuery(myQueryOptions)// useInfiniteQuery(myQueryOptions)// Create MutationOptions which can be passed to useMutationconstmyMutationOptions =trpc .path .to .mutation .mutationOptions ()constmyMutation =useMutation (myMutationOptions )// Create a QueryKey which can be used to manipulate many methods// on TanStack's QueryClient in a type-safe mannerconstmyQueryKey =trpc .path .to .query .queryKey ()constinvalidateMyQueryKey = () => {queryClient .invalidateQueries ({queryKey :myQueryKey })}return (// Your app herenull)}
trpc 객체는 완전히 타입 안전하며 AppRouter의 모든 프로시저에 대한 자동완성을 제공합니다. 프록시 끝에 다음 메서드들이 사용할 수 있습니다:
queryOptions - 데이터 쿼리
모든 쿼리 프로시저에서 사용할 수 있습니다. TanStack의 queryOptions 함수를 감싸는 타입 안전한 래퍼를 제공합니다. 첫 번째 인수는 프로시저의 입력이며, 두 번째 인수에는 네이티브 TanStack React Query 옵션을 모두 전달할 수 있습니다.
tsconstqueryOptions =trpc .path .to .query .queryOptions ({/** input */id : 'foo',},{// Any Tanstack React Query optionsstaleTime : 1000,},);
tsconstqueryOptions =trpc .path .to .query .queryOptions ({/** input */id : 'foo',},{// Any Tanstack React Query optionsstaleTime : 1000,},);
클라이언트에 tRPC 요청 옵션을 제공하기 위해 queryOptions 함수에 trpc 객체를 추가로 제공할 수 있습니다.
tsconstqueryOptions =trpc .path .to .query .queryOptions ({/** input */id : 'foo',},{trpc : {// Provide tRPC request options to the clientcontext : {// see https://trpc.io/docs/client/links#managing-context},},},);
tsconstqueryOptions =trpc .path .to .query .queryOptions ({/** input */id : 'foo',},{trpc : {// Provide tRPC request options to the clientcontext : {// see https://trpc.io/docs/client/links#managing-context},},},);
쿼리를 타입 안전하게 비활성화하려면 skipToken을 사용할 수 있습니다:
tsconstquery =useQuery (trpc .user .details .queryOptions (user ?.id &&project ?.id ? {userId :user .id ,projectId :project .id ,}:skipToken ,{staleTime : 1000,},),);
tsconstquery =useQuery (trpc .user .details .queryOptions (user ?.id &&project ?.id ? {userId :user .id ,projectId :project .id ,}:skipToken ,{staleTime : 1000,},),);
결과는 useQuery 또는 useSuspenseQuery 훅이나 fetchQuery, prefetchQuery, prefetchInfiniteQuery, invalidateQueries 등 쿼리 클라이언트 메서드에 전달할 수 있습니다.
infiniteQueryOptions - 무한 데이터 쿼리
커서 입력을 받는 모든 쿼리 프로시저에서 사용할 수 있습니다. TanStack의 infiniteQueryOptions 함수를 감싸는 타입 안전한 래퍼를 제공합니다. 첫 번째 인수는 프로시저의 입력이며, 두 번째 인수에는 네이티브 TanStack React Query 옵션을 모두 전달할 수 있습니다.
tsconstinfiniteQueryOptions =trpc .path .to .query .infiniteQueryOptions ({/** input */},{// Any Tanstack React Query optionsgetNextPageParam : (lastPage ,pages ) =>lastPage .nextCursor ,},);
tsconstinfiniteQueryOptions =trpc .path .to .query .infiniteQueryOptions ({/** input */},{// Any Tanstack React Query optionsgetNextPageParam : (lastPage ,pages ) =>lastPage .nextCursor ,},);
queryKey - 쿼리 키 가져오기 및 쿼리 클라이언트에서 작업 수행
모든 쿼리 프로시저에서 사용할 수 있습니다. 쿼리 키에 타입 안전하게 접근할 수 있습니다.
tsconstqueryKey =trpc .path .to .query .queryKey ();
tsconstqueryKey =trpc .path .to .query .queryKey ();
TanStack React Query는 쿼리 키에 퍼지 매칭을 사용하므로, 하위 경로의 부분 쿼리 키를 만들어 라우터에 속한 모든 쿼리와 일치시킬 수도 있습니다:
tsconstqueryKey =trpc .router .pathKey ();
tsconstqueryKey =trpc .router .pathKey ();
또는 모든 tRPC 쿼리를 일치시키기 위해 루트 경로를 사용할 수도 있습니다:
tsconstqueryKey =trpc .pathKey ();
tsconstqueryKey =trpc .pathKey ();
infiniteQueryKey - 무한 쿼리 키 가져오기
커서 입력을 받는 모든 쿼리 프로시저에서 사용할 수 있습니다. 무한 쿼리의 쿼리 키에 타입 안전하게 접근할 수 있습니다.
tsconstinfiniteQueryKey =trpc .path .to .query .infiniteQueryKey ({/** input */});
tsconstinfiniteQueryKey =trpc .path .to .query .infiniteQueryKey ({/** input */});
결과는 getQueryData, setQueryData, invalidateQueries 등 쿼리 클라이언트 메서드와 함께 사용할 수 있습니다.
ts// Get cached data for an infinite queryconstcachedData =queryClient .getQueryData (trpc .path .to .query .infiniteQueryKey ({cursor : 0 }),);// Set cached data for an infinite queryqueryClient .setQueryData (trpc .path .to .query .infiniteQueryKey ({cursor : 0 }),(data ) => {// Modify the datareturndata ;},);
ts// Get cached data for an infinite queryconstcachedData =queryClient .getQueryData (trpc .path .to .query .infiniteQueryKey ({cursor : 0 }),);// Set cached data for an infinite queryqueryClient .setQueryData (trpc .path .to .query .infiniteQueryKey ({cursor : 0 }),(data ) => {// Modify the datareturndata ;},);
queryFilter - 쿼리 필터 생성
모든 쿼리 프로시저에서 사용할 수 있습니다. 쿼리 필터를 타입 안전하게 생성할 수 있습니다.
tsconstqueryFilter =trpc .path .to .query .queryFilter ({/** input */},{// Any Tanstack React Query filterpredicate : (query ) => {return !!query .state .data ;},},);
tsconstqueryFilter =trpc .path .to .query .queryFilter ({/** input */},{// Any Tanstack React Query filterpredicate : (query ) => {return !!query .state .data ;},},);
쿼리 키와 마찬가지로, 라우터 전체에 걸쳐 필터를 실행하려면 pathFilter를 사용하여 하위 경로를 지정할 수 있습니다.
tsconstqueryFilter =trpc .path .pathFilter ({// Any Tanstack React Query filterpredicate : (query ) => {return !!query .state .data ;},});
tsconstqueryFilter =trpc .path .pathFilter ({// Any Tanstack React Query filterpredicate : (query ) => {return !!query .state .data ;},});
queryClient.invalidateQueries 등 클라이언트 메서드에 전달할 수 있는 필터를 생성하는 데 유용합니다.
infiniteQueryFilter - 무한 쿼리 필터 생성
커서 입력을 받는 모든 쿼리 프로시저에서 사용할 수 있습니다. 무한 쿼리에 대한 쿼리 필터를 타입 안전하게 생성할 수 있습니다.
tsconstinfiniteQueryFilter =trpc .path .to .query .infiniteQueryFilter ({/** input */},{// Any Tanstack React Query filterpredicate : (query ) => {return !!query .state .data ;},},);
tsconstinfiniteQueryFilter =trpc .path .to .query .infiniteQueryFilter ({/** input */},{// Any Tanstack React Query filterpredicate : (query ) => {return !!query .state .data ;},},);
queryClient.invalidateQueries 등 클라이언트 메서드에 전달할 수 있는 필터를 생성하는 데 유용합니다.
tsawaitqueryClient .invalidateQueries (trpc .path .to .query .infiniteQueryFilter ({},{predicate : (query ) => {// Filter logic based on query statereturnquery .state .status === 'success';},},),);
tsawaitqueryClient .invalidateQueries (trpc .path .to .query .infiniteQueryFilter ({},{predicate : (query ) => {// Filter logic based on query statereturnquery .state .status === 'success';},},),);
mutationOptions - 뮤테이션 옵션 생성
모든 뮤테이션 프로시저에서 사용할 수 있습니다. useMutation에 전달할 수 있는 옵션을 구성하기 위한 타입 안전한 항등 함수를 제공합니다.
tsconstmutationOptions =trpc .path .to .mutation .mutationOptions ({// Any Tanstack React Query optionsonSuccess : (data ) => {// do something with the data},});
tsconstmutationOptions =trpc .path .to .mutation .mutationOptions ({// Any Tanstack React Query optionsonSuccess : (data ) => {// do something with the data},});
mutationKey - 뮤테이션 키 가져오기
모든 뮤테이션 프로시저에서 사용할 수 있습니다. 뮤테이션 키를 타입 안전하게 가져올 수 있습니다.
tsconstmutationKey =trpc .path .to .mutation .mutationKey ();
tsconstmutationKey =trpc .path .to .mutation .mutationKey ();
subscriptionOptions - 구독 옵션 생성
TanStack은 구독 훅을 제공하지 않으므로, 표준 tRPC 구독 설정과 함께 작동하는 자체 추상화를 계속 노출합니다.
모든 구독 프로시저에서 사용할 수 있습니다. useSubscription에 전달할 수 있는 옵션을 구성하기 위한 타입 안전한 항등 함수를 제공합니다.
구독을 사용하려면 tRPC 클라이언트에 httpSubscriptionLink 또는 wsLink 중 하나가 설정되어 있어야 합니다.
tsxfunctionSubscriptionExample () {consttrpc =useTRPC ();constsubscription =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 heresubscription .data ; // The lastly received datasubscription .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 <>{/* ... */}</>;}
tsxfunctionSubscriptionExample () {consttrpc =useTRPC ();constsubscription =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 heresubscription .data ; // The lastly received datasubscription .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 <>{/* ... */}</>;}
쿼리 키 접두사 추가
단일 애플리케이션에서 여러 tRPC 프로바이더를 사용하는 경우(예: 다른 백엔드 서비스에 연결하는 경우), 동일한 경로를 가진 쿼리가 캐시에서 충돌할 수 있습니다. 쿼리 키 접두사 추가를 활성화하여 이를 방지할 수 있습니다.
tsx// Without prefixes - these would collide!constauthQuery =useQuery (trpcAuth .list .queryOptions ()); // auth serviceconstbillingQuery =useQuery (trpcBilling .list .queryOptions ()); // billing service
tsx// Without prefixes - these would collide!constauthQuery =useQuery (trpcAuth .list .queryOptions ()); // auth serviceconstbillingQuery =useQuery (trpcBilling .list .queryOptions ()); // billing service
컨텍스트를 생성할 때 기능 플래그를 활성화합니다:
utils/trpc.tstsx// [...]constbilling =createTRPCContext <BillingRouter , {keyPrefix : true }>();export constBillingProvider =billing .TRPCProvider ;export constuseBilling =billing .useTRPC ;export constcreateBillingClient = () =>createTRPCClient <BillingRouter >({links : [/* ... */],});constaccount =createTRPCContext <AccountRouter , {keyPrefix : true }>();export constAccountProvider =account .TRPCProvider ;export constuseAccount =account .useTRPC ;export constcreateAccountClient = () =>createTRPCClient <AccountRouter >({links : [/* ... */],});
utils/trpc.tstsx// [...]constbilling =createTRPCContext <BillingRouter , {keyPrefix : true }>();export constBillingProvider =billing .TRPCProvider ;export constuseBilling =billing .useTRPC ;export constcreateBillingClient = () =>createTRPCClient <BillingRouter >({links : [/* ... */],});constaccount =createTRPCContext <AccountRouter , {keyPrefix : true }>();export constAccountProvider =account .TRPCProvider ;export constuseAccount =account .useTRPC ;export constcreateAccountClient = () =>createTRPCClient <AccountRouter >({links : [/* ... */],});
App.tsxtsximport {useState } from 'react';import {QueryClient ,QueryClientProvider } from '@tanstack/react-query';import {BillingProvider ,AccountProvider ,createBillingClient ,createAccountClient ,} from './utils/trpc';// [...]export functionApp () {const [queryClient ] =useState (() => newQueryClient ());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"><div >{/* ... */}</div ></AccountProvider ></BillingProvider ></QueryClientProvider >);}
App.tsxtsximport {useState } from 'react';import {QueryClient ,QueryClientProvider } from '@tanstack/react-query';import {BillingProvider ,AccountProvider ,createBillingClient ,createAccountClient ,} from './utils/trpc';// [...]export functionApp () {const [queryClient ] =useState (() => newQueryClient ());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"><div >{/* ... */}</div ></AccountProvider ></BillingProvider ></QueryClientProvider >);}
components/MyComponent.tsxtsximport {useQuery } from '@tanstack/react-query';import {useBilling ,useAccount } from '../utils/trpc';// [...]export functionMyComponent () {constbilling =useBilling ();constaccount =useAccount ();constbillingList =useQuery (billing .list .queryOptions ());constaccountList =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.tsxtsximport {useQuery } from '@tanstack/react-query';import {useBilling ,useAccount } from '../utils/trpc';// [...]export functionMyComponent () {constbilling =useBilling ();constaccount =useAccount ();constbillingList =useQuery (billing .list .queryOptions ());constaccountList =useQuery (account .list .queryOptions ());return (<div ><div >Billing: {JSON .stringify (billingList .data ?? null)}</div ><div >Account: {JSON .stringify (accountList .data ?? null)}</div ></div >);}
쿼리 키에 접두사가 올바르게 추가되어 충돌을 방지합니다:
tsx// Example of how the query keys look with prefixesconstqueryKeys = [[['billing'], ['list'], {type : 'query' }],[['account'], ['list'], {type : 'query' }],];
tsx// Example of how the query keys look with prefixesconstqueryKeys = [[['billing'], ['list'], {type : 'query' }],[['account'], ['list'], {type : 'query' }],];
입력 및 출력 타입 추론
프로시저 또는 라우터의 입력과 출력 타입을 추론해야 하는 경우, 상황에 따라 두 가지 옵션이 있습니다.
전체 라우터의 입력 및 출력 타입 추론
tsimport type {inferRouterInputs ,inferRouterOutputs } from '@trpc/server';import type {AppRouter } from './server/router';export typeInputs =inferRouterInputs <AppRouter >;export typeOutputs =inferRouterOutputs <AppRouter >;
tsimport type {inferRouterInputs ,inferRouterOutputs } from '@trpc/server';import type {AppRouter } from './server/router';export typeInputs =inferRouterInputs <AppRouter >;export typeOutputs =inferRouterOutputs <AppRouter >;
단일 프로시저의 타입 추론
tsimport type {inferInput ,inferOutput } from '@trpc/tanstack-react-query';functionComponent () {consttrpc =useTRPC ();typeInput =inferInput <typeoftrpc .path .to .procedure >;typeOutput =inferOutput <typeoftrpc .path .to .procedure >;}
tsimport type {inferInput ,inferOutput } from '@trpc/tanstack-react-query';functionComponent () {consttrpc =useTRPC ();typeInput =inferInput <typeoftrpc .path .to .procedure >;typeOutput =inferOutput <typeoftrpc .path .to .procedure >;}
tRPC 클라이언트 접근
React Context를 사용한 설정을 사용했다면, useTRPCClient 훅을 사용하여 tRPC 클라이언트에 접근할 수 있습니다.
tsximport {useTRPCClient } from './trpc';async functionComponent () {consttrpcClient =useTRPCClient ();constresult = awaittrpcClient .getUser .query ({id : '1',});}
tsximport {useTRPCClient } from './trpc';async functionComponent () {consttrpcClient =useTRPCClient ();constresult = awaittrpcClient .getUser .query ({id : '1',});}
React Context 없이 설정한 경우, 대신 전역 클라이언트 인스턴스를 직접 가져올 수 있습니다.
tsimport {client } from './trpc';constresult = awaitclient .path .to .procedure .query ({/** input */id : 'foo',});
tsimport {client } from './trpc';constresult = awaitclient .path .to .procedure .query ({/** input */id : 'foo',});