メインコンテンツへスキップ
バージョン: 11.x

useQuery()

非公式ベータ版翻訳

このページは PageTurner AI で翻訳されました(ベータ版)。プロジェクト公式の承認はありません。 エラーを見つけましたか? 問題を報告 →

useQueryはデータ取得の主要なフックで、@tanstack/react-queryuseQueryと同様に動作しますが、trpc固有のオプションやストリーミングなどの追加機能が含まれています。

注記

オプションや使用パターンの詳細については、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を拡張しているため、enabledrefetchOnWindowFocusなど任意のオプションが使用できます。さらに、プロシージャごとの挙動を制御するtrpc固有のオプションも提供しています:

  • trpc.ssr: グローバル設定ssr: trueを指定している場合、この特定のクエリでSSRを無効化するにはfalseを設定できます。※逆方向の動作はサポートされません。つまり、グローバル設定がfalseの場合、プロシージャ単位でSSRを有効化することはできません。

  • trpc.abortOnUnmount: グローバル設定を上書きし、アンマウント時にクエリを中止するかどうかを選択します。

  • trpc.context: リンクで使用できる追加メタデータを付与します。

ヒント

オプションを設定したいが入力値を渡したくない場合、代わりにundefinedを渡せます。

バックエンドで設定したinputスキーマに基づき、inputに対するオートコンプリートが機能することに気づくでしょう。

使用例

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

asyncジェネレータを用いたストリーミングレスポンス

情報

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]