TanStack React Query
이 페이지는 PageTurner AI로 번역되었습니다(베타). 프로젝트 공식 승인을 받지 않았습니다. 오류를 발견하셨나요? 문제 신고 →
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.
간단한 예제 쿼리
tsximport { 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'}
tsximport { 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'}
사용법
이 클라이언트의 철학은 Tanstack React Query와 기본적으로 그리고 타입 안전하게 작동하는 간결하고 타입 안전한 팩토리를 제공하는 것입니다. 이는 클라이언트가 제공하는 자동 완성을 따르기만 하면 TanStack React Query 문서에서 제공하는 지식만으로도 개발에 집중할 수 있음을 의미합니다.
tsxexport default function Basics() {const trpc = useTRPC();const queryClient = useQueryClient();// Create QueryOptions which can be passed to query hooksconst myQueryOptions = trpc.path.to.query.queryOptions({ /** inputs */ })const myQuery = useQuery(myQueryOptions)// or:// useSuspenseQuery(myQueryOptions)// useInfiniteQuery(myQueryOptions)// Create MutationOptions which can be passed to useMutationconst 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 mannerconst myQueryKey = trpc.path.to.query.queryKey()const invalidateMyQueryKey = () => {queryClient.invalidateQueries({ queryKey: myQueryKey })}return (// Your app here)}
tsxexport default function Basics() {const trpc = useTRPC();const queryClient = useQueryClient();// Create QueryOptions which can be passed to query hooksconst myQueryOptions = trpc.path.to.query.queryOptions({ /** inputs */ })const myQuery = useQuery(myQueryOptions)// or:// useSuspenseQuery(myQueryOptions)// useInfiniteQuery(myQueryOptions)// Create MutationOptions which can be passed to useMutationconst 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 mannerconst myQueryKey = trpc.path.to.query.queryKey()const invalidateMyQueryKey = () => {queryClient.invalidateQueries({ queryKey: myQueryKey })}return (// Your app here)}
trpc 객체는 완전히 타입 안전하며 AppRouter의 모든 프로시저에 대한 자동 완성을 제공합니다. 프록시 체인의 끝에서 다음 메서드들을 사용할 수 있습니다:
queryOptions - 데이터 쿼리
모든 쿼리 프로시저에서 사용 가능합니다. Tanstack의 queryOptions 함수를 타입 안전하게 감싼 래퍼를 제공합니다. 첫 번째 인자는 프로시저 입력값이고, 두 번째 인자는 기본 Tanstack React Query 옵션을 받습니다.
tsconst queryOptions = trpc.path.to.query.queryOptions({/** input */},{// Any Tanstack React Query optionsstaleTime: 1000,},);
tsconst queryOptions = trpc.path.to.query.queryOptions({/** input */},{// Any Tanstack React Query optionsstaleTime: 1000,},);
queryOptions 함수에 trpc 객체를 추가로 제공하여 클라이언트에 tRPC 요청 옵션을 전달할 수 있습니다.
tsconst queryOptions = trpc.path.to.query.queryOptions({/** input */},{trpc: {// Provide tRPC request options to the clientcontext: {// see https://trpc.io/docs/client/links#managing-context},},},);
tsconst queryOptions = trpc.path.to.query.queryOptions({/** input */},{trpc: {// Provide tRPC request options to the clientcontext: {// see https://trpc.io/docs/client/links#managing-context},},},);
타입 안전한 방식으로 쿼리를 비활성화하려면 skipToken을 사용할 수 있습니다:
tsimport { 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,},),);
tsimport { 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,},),);
결과는 useQuery 또는 useSuspenseQuery 훅이나 fetchQuery, prefetchQuery, prefetchInfiniteQuery, invalidateQueries 등의 쿼리 클라이언트 메서드에 전달될 수 있습니다.
infiniteQueryOptions - 무한 데이터 쿼리
커서 입력을 받는 모든 쿼리 프로시저에서 사용 가능합니다. Tanstack의 infiniteQueryOptions 함수를 타입 안전하게 감싼 래퍼를 제공합니다. 첫 번째 인자는 프로시저 입력값이고, 두 번째 인자는 기본 Tanstack React Query 옵션을 받습니다.
tsconst infiniteQueryOptions = trpc.path.to.query.infiniteQueryOptions({/** input */},{// Any Tanstack React Query optionsgetNextPageParam: (lastPage, pages) => lastPage.nextCursor,},);
tsconst infiniteQueryOptions = trpc.path.to.query.infiniteQueryOptions({/** input */},{// Any Tanstack React Query optionsgetNextPageParam: (lastPage, pages) => lastPage.nextCursor,},);
queryKey - 쿼리 키 가져오기 및 쿼리 클라이언트 작업 수행
모든 쿼리 프로시저에서 사용 가능합니다. 타입 안전한 방식으로 쿼리 키에 접근할 수 있습니다.
tsconst queryKey = trpc.path.to.query.queryKey();
tsconst queryKey = trpc.path.to.query.queryKey();
Tanstack React Query가 쿼리 키에 퍼지 매칭을 사용하므로, 특정 라우터에 속한 모든 쿼리를 일치시키기 위해 서브 경로에 대한 부분 쿼리 키를 생성할 수도 있습니다:
tsconst queryKey = trpc.router.pathKey();
tsconst queryKey = trpc.router.pathKey();
모든 tRPC 쿼리를 일치시키기 위해 루트 경로로도 생성할 수 있습니다:
tsconst queryKey = trpc.pathKey();
tsconst queryKey = trpc.pathKey();
infiniteQueryKey - 무한 쿼리 키 가져오기
커서 입력을 받는 모든 쿼리 프로시저에서 사용 가능합니다. 타입 안전한 방식으로 무한 쿼리의 쿼리 키에 접근할 수 있습니다.
tsconst infiniteQueryKey = trpc.path.to.query.infiniteQueryKey({/** input */});
tsconst infiniteQueryKey = trpc.path.to.query.infiniteQueryKey({/** input */});
결과는 getQueryData, setQueryData, invalidateQueries 등의 쿼리 클라이언트 메서드에 사용될 수 있습니다.
tsconst queryClient = useQueryClient();// Get cached data for an infinite queryconst cachedData = 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 datareturn data;},);
tsconst queryClient = useQueryClient();// Get cached data for an infinite queryconst cachedData = 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 datareturn data;},);
queryFilter - 쿼리 필터 생성
모든 쿼리 프로시저에서 사용 가능합니다. 타입 안전한 방식으로 쿼리 필터를 생성할 수 있습니다.
tsconst queryFilter = trpc.path.to.query.queryFilter({/** input */},{// Any Tanstack React Query filterpredicate: (query) => {query.state.data;},},);
tsconst queryFilter = trpc.path.to.query.queryFilter({/** input */},{// Any Tanstack React Query filterpredicate: (query) => {query.state.data;},},);
쿼리 키와 마찬가지로, 전체 라우터에 걸쳐 필터를 적용하려면 pathFilter를 사용해 특정 서브 경로를 대상으로 지정할 수 있습니다.
tsconst queryFilter = trpc.path.pathFilter({// Any Tanstack React Query filterpredicate: (query) => {query.state.data;},});
tsconst queryFilter = trpc.path.pathFilter({// Any Tanstack React Query filterpredicate: (query) => {query.state.data;},});
queryClient.invalidateQueries 등과 같은 클라이언트 메서드에 전달할 수 있는 필터를 생성하는 데 유용합니다.
infiniteQueryFilter - 무한 쿼리 필터 생성
커서 입력을 받는 모든 쿼리 프로시저에서 사용 가능합니다. 타입 안전한 방식으로 무한 쿼리에 대한 쿼리 필터를 생성할 수 있습니다.
tsconst infiniteQueryFilter = trpc.path.to.query.infiniteQueryFilter({/** input */},{// Any Tanstack React Query filterpredicate: (query) => {query.state.data;},},);
tsconst infiniteQueryFilter = trpc.path.to.query.infiniteQueryFilter({/** input */},{// Any Tanstack React Query filterpredicate: (query) => {query.state.data;},},);
queryClient.invalidateQueries 등과 같은 클라이언트 메서드에 전달할 수 있는 필터를 생성하는 데 유용합니다.
tsawait queryClient.invalidateQueries(trpc.path.to.query.infiniteQueryFilter({},{predicate: (query) => {// Filter logic based on query statereturn query.state.data?.pages.length > 0;},},),);
tsawait queryClient.invalidateQueries(trpc.path.to.query.infiniteQueryFilter({},{predicate: (query) => {// Filter logic based on query statereturn query.state.data?.pages.length > 0;},},),);
mutationOptions - 뮤테이션 옵션 생성
모든 뮤테이션 프로시저에서 사용 가능합니다. useMutation에 전달할 수 있는 옵션을 구성하기 위한 타입 안전한 식별 함수를 제공합니다.
tsconst mutationOptions = trpc.path.to.mutation.mutationOptions({// Any Tanstack React Query optionsonSuccess: (data) => {// do something with the data},});
tsconst mutationOptions = trpc.path.to.mutation.mutationOptions({// Any Tanstack React Query optionsonSuccess: (data) => {// do something with the data},});
mutationKey - 뮤테이션 키 가져오기
모든 뮤테이션 프로시저에서 사용 가능합니다. 타입 안전한 방식으로 뮤테이션 키를 가져올 수 있습니다.
tsconst mutationKey = trpc.path.to.mutation.mutationKey();
tsconst mutationKey = trpc.path.to.mutation.mutationKey();
subscriptionOptions - 구독 옵션 생성
TanStack은 구독 훅을 제공하지 않으므로, 표준 tRPC 구독 설정과 호환되는 자체 추상화를 계속 제공합니다. 모든 구독 프로시저에서 사용 가능하며 useSubscription에 전달할 수 있는 옵션을 구성하기 위한 타입 안전한 식별 함수를 제공합니다. 구독을 사용하려면 tRPC 클라이언트에 httpSubscriptionLink 또는 wsLink 중 하나가 구성되어 있어야 합니다.
tsxfunction 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 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 <>{/* ... */}</>;}
tsxfunction 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 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!const authQuery = useQuery(trpcAuth.list.queryOptions()); // auth serviceconst billingQuery = useQuery(trpcBilling.list.queryOptions()); // billing service
tsx// Without prefixes - these would collide!const authQuery = useQuery(trpcAuth.list.queryOptions()); // auth serviceconst billingQuery = useQuery(trpcBilling.list.queryOptions()); // billing service
컨텍스트 생성 시 기능 플래그를 활성화하세요:
utils/trpc.tstsx// [...]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.tstsx// [...]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.tsxtsx// [...]export function App() {const [queryClient] = useState(() => new QueryClient());const [billingClient] = useState(() => createBillingClient());const [accountClient] = useState(() => createAccountClient());return (<QueryClientProvider client={queryClient}><BillingProvidertrpcClient={billingClient}queryClient={queryClient}keyPrefix="billing"><AccountProvidertrpcClient={accountClient}queryClient={queryClient}keyPrefix="account">{/* ... */}</AccountProvider></BillingProvider></QueryClientProvider>);}
App.tsxtsx// [...]export function App() {const [queryClient] = useState(() => new QueryClient());const [billingClient] = useState(() => createBillingClient());const [accountClient] = useState(() => createAccountClient());return (<QueryClientProvider client={queryClient}><BillingProvidertrpcClient={billingClient}queryClient={queryClient}keyPrefix="billing"><AccountProvidertrpcClient={accountClient}queryClient={queryClient}keyPrefix="account">{/* ... */}</AccountProvider></BillingProvider></QueryClientProvider>);}
components/MyComponent.tsxtsx// [...]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.tsxtsx// [...]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>);}
쿼리 키가 적절히 프리픽스되어 충돌을 방지합니다:
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 { AppRouter } from './path/to/server';export type Inputs = inferRouterInputs<AppRouter>;export type Outputs = inferRouterOutputs<AppRouter>;
tsimport type { inferRouterInputs, inferRouterOutputs } from '@trpc/server';import { AppRouter } from './path/to/server';export type Inputs = inferRouterInputs<AppRouter>;export type Outputs = inferRouterOutputs<AppRouter>;
단일 프로시저에 대한 타입 추론
tsimport 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>;}
tsimport 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>;}
tRPC 클라이언트 접근하기
React Context를 사용한 설정을 사용했다면, useTRPCClient 훅으로 tRPC 클라이언트에 접근할 수 있습니다.
tsximport { useTRPCClient } from './trpc';function Component() {const trpcClient = useTRPCClient();const result = await trpcClient.path.to.procedure.query({/** input */});}
tsximport { useTRPCClient } from './trpc';function Component() {const trpcClient = useTRPCClient();const result = await trpcClient.path.to.procedure.query({/** input */});}
React Context 없이 설정한 경우에는 전역 클라이언트 인스턴스를 직접 임포트하면 됩니다.
tsimport { client } from './trpc';const result = await client.path.to.procedure.query({/** input */});
tsimport { client } from './trpc';const result = await client.path.to.procedure.query({/** input */});