본문으로 건너뛰기
버전: 11.x

useQuery()

useQuery는 데이터 가져오기를 위한 주요 훅으로, @tanstack/react-queryuseQuery와 유사하게 작동하지만 trpc에 특화된 옵션과 스트리밍과 같은 추가 기능을 제공합니다.

노트

옵션 및 사용 패턴에 대한 자세한 정보는 queries에 있는 TanStack Query 문서를 참조하세요.

시그니처

tsx
declare function useQuery(
input: TInput | SkipToken,
opts?: UseTRPCQueryOptions,
): void;
 
interface UseTRPCQueryOptions
extends UseQueryOptions {
trpc: {
ssr?: boolean;
abortOnUnmount?: boolean;
context?: Record<string, unknown>;
}
}
tsx
declare function useQuery(
input: TInput | SkipToken,
opts?: UseTRPCQueryOptions,
): void;
 
interface UseTRPCQueryOptions
extends UseQueryOptions {
trpc: {
ssr?: boolean;
abortOnUnmount?: boolean;
context?: Record<string, unknown>;
}
}

UseTRPCQueryOptions@tanstack/react-queryUseQueryOptions 타입을 확장하므로 enabled, refetchOnWindowFocus 등의 옵션을 모두 사용할 수 있습니다. 또한 프로시저별 동작을 활성화하거나 비활성화하는 trpc 전용 옵션도 제공합니다:

  • trpc.ssr: global configssr: true가 설정되어 있는 경우, 이 값을 false로 설정하여 해당 쿼리에 대한 ssr을 비활성화할 수 있습니다. 이 설정은 역방향으로 작동하지 않으므로, global config가 false로 설정되어 있으면 프로시저에서 ssr을 활성화할 수 없습니다.
  • trpc.abortOnUnmount: global config를 오버라이드하여 언마운트 시 쿼리 중단 여부를 선택할 수 있습니다.
  • trpc.context: Links에서 사용할 수 있는 추가 메타데이터를 추가합니다.

옵션을 설정해야 하지만 입력을 전달하지 않으려면 undefined를 대신 전달할 수 있습니다.

백엔드에서 설정한 input 스키마에 따라 input에 대한 자동완성을 받을 수 있습니다.

사용 예시

백엔드 코드
server/routers/_app.ts
tsx
import { initTRPC } from '@trpc/server';
import { z } from 'zod';
 
export const t = initTRPC.create();
 
export const appRouter = t.router({
// Create procedure at path 'hello'
hello: t.procedure
// using zod schema to validate and infer input values
.input(
z
.object({
text: z.string().nullish(),
})
.nullish(),
)
.query((opts) => {
return {
greeting: `hello ${opts.input?.text ?? 'world'}`,
};
}),
});
 
export type AppRouter = typeof appRouter;
server/routers/_app.ts
tsx
import { initTRPC } from '@trpc/server';
import { z } from 'zod';
 
export const t = initTRPC.create();
 
export const appRouter = t.router({
// Create procedure at path 'hello'
hello: t.procedure
// using zod schema to validate and infer input values
.input(
z
.object({
text: z.string().nullish(),
})
.nullish(),
)
.query((opts) => {
return {
greeting: `hello ${opts.input?.text ?? 'world'}`,
};
}),
});
 
export type AppRouter = typeof appRouter;
components/MyComponent.tsx
tsx
import { trpc } from '../utils/trpc';
 
export function MyComponent() {
// input is optional, so we don't have to pass second argument
const helloNoArgs = trpc.hello.useQuery();
const helloWithArgs = trpc.hello.useQuery({ text: 'client' });
 
return (
<div>
<h1>Hello World Example</h1>
<ul>
<li>
helloNoArgs ({helloNoArgs.status}):{' '}
<pre>{JSON.stringify(helloNoArgs.data, null, 2)}</pre>
</li>
<li>
helloWithArgs ({helloWithArgs.status}):{' '}
<pre>{JSON.stringify(helloWithArgs.data, null, 2)}</pre>
</li>
</ul>
</div>
);
}
components/MyComponent.tsx
tsx
import { trpc } from '../utils/trpc';
 
export function MyComponent() {
// input is optional, so we don't have to pass second argument
const helloNoArgs = trpc.hello.useQuery();
const helloWithArgs = trpc.hello.useQuery({ text: 'client' });
 
return (
<div>
<h1>Hello World Example</h1>
<ul>
<li>
helloNoArgs ({helloNoArgs.status}):{' '}
<pre>{JSON.stringify(helloNoArgs.data, null, 2)}</pre>
</li>
<li>
helloWithArgs ({helloWithArgs.status}):{' '}
<pre>{JSON.stringify(helloWithArgs.data, null, 2)}</pre>
</li>
</ul>
</div>
);
}

비동기 생성기를 사용한 스트리밍 응답

정보

v11부터 httpBatchStreamLink를 사용할 때 스트리밍 쿼리를 지원합니다.

쿼리에서 비동기 생성기를 반환하면 다음과 같은 동작을 수행합니다:

  • 응답이 들어오는 동안 업데이트되는 배열 형태로 data 속성에 반복자의 결과를 가져옵니다
  • 첫 번째 청크가 수신되는 즉시 statussuccess 상태가 됩니다.
  • 마지막 청크가 수신될 때까지 fetchStatus 속성이 fetching 상태가 됩니다.

예시

server/routers/_app.ts
tsx
import { initTRPC } from '@trpc/server';
 
const t = initTRPC.create();
 
const appRouter = t.router({
iterable: t.procedure.query(async function* () {
for (let i = 0; i < 3; i++) {
await new Promise((resolve) => setTimeout(resolve, 500));
yield i;
}
}),
});
 
export type AppRouter = typeof appRouter;
server/routers/_app.ts
tsx
import { initTRPC } from '@trpc/server';
 
const t = initTRPC.create();
 
const appRouter = t.router({
iterable: t.procedure.query(async function* () {
for (let i = 0; i < 3; i++) {
await new Promise((resolve) => setTimeout(resolve, 500));
yield i;
}
}),
});
 
export type AppRouter = typeof appRouter;
components/MyComponent.tsx
tsx
import React, { Fragment } from 'react';
import { trpc } from '../utils/trpc';
 
export function MyComponent() {
const result = trpc.iterable.useQuery();
 
return (
<div>
{result.data?.map((chunk, index) => (
<Fragment key={index}>{chunk}</Fragment>
))}
</div>
);
}
components/MyComponent.tsx
tsx
import React, { Fragment } from 'react';
import { trpc } from '../utils/trpc';
 
export function MyComponent() {
const result = trpc.iterable.useQuery();
 
return (
<div>
{result.data?.map((chunk, index) => (
<Fragment key={index}>{chunk}</Fragment>
))}
</div>
);
}

스트리밍 중 result 속성:

statusfetchStatusdata
'pending''fetching'undefined
'success''fetching'[]
'success''fetching'[0]
'success''fetching'[0, 1]
'success''fetching'[0, 1, 2]
'success''idle'[0, 1, 2]