useUtils
このページは PageTurner AI で翻訳されました(ベータ版)。プロジェクト公式の承認はありません。 エラーを見つけましたか? 問題を報告 →
useUtilsは、@trpc/react-query経由で実行したクエリのキャッシュデータを管理するヘルパーにアクセスできるフックです。これらのヘルパーは実際には@tanstack/react-queryのqueryClientメソッドのシンラッパーです。ここで提供する情報よりも詳細なuseUtilsヘルパーのオプションや使用パターンについては、各@tanstack/react-queryドキュメントにリンクしているので適宜参照してください。
このフックは10.41.0までuseContext()と呼ばれていました(今後も当面はエイリアスとして利用可能です)
使用方法
useUtilsはルーター内の全利用可能なクエリを含むオブジェクトを返します。使用方法はtrpcクライアントオブジェクトと同じです。クエリに到達するとクエリヘルパーにアクセスできます。例として、allクエリを持つpostルーターがあるとします:
server.tsts// @filename: server.tsimport {initTRPC } from '@trpc/server';import {z } from 'zod';constt =initTRPC .create ();constappRouter =t .router ({post :t .router ({all :t .procedure .query (() => {return {posts : [{id : 1,title : 'everlong' },{id : 2,title : 'After Dark' },],};}),}),});export typeAppRouter = typeofappRouter ;
server.tsts// @filename: server.tsimport {initTRPC } from '@trpc/server';import {z } from 'zod';constt =initTRPC .create ();constappRouter =t .router ({post :t .router ({all :t .procedure .query (() => {return {posts : [{id : 1,title : 'everlong' },{id : 2,title : 'After Dark' },],};}),}),});export typeAppRouter = typeofappRouter ;
コンポーネント内でuseUtilsから取得したオブジェクトを操作しpost.allクエリに到達すると、クエリヘルパーにアクセスできます!
MyComponent.tsxtsxfunctionMyComponent () {constutils =trpc .useUtils ();utils .post .all .f ;// [...]}
MyComponent.tsxtsxfunctionMyComponent () {constutils =trpc .useUtils ();utils .post .all .f ;// [...]}
ヘルパー
以下はuseUtils経由でアクセス可能なヘルパーです。下記の表は各tRPCヘルパーがどの@tanstack/react-queryヘルパーメソッドをラップしているかを示します。各react-queryメソッドは対応するドキュメント/ガイドにリンクしています:
| tRPC helper wrapper | @tanstack/react-query helper method |
|---|---|
fetch | queryClient.fetchQuery |
prefetch | queryClient.prefetchQuery |
fetchInfinite | queryClient.fetchInfiniteQuery |
prefetchInfinite | queryClient.prefetchInfiniteQuery |
ensureData | queryClient.ensureData |
invalidate | queryClient.invalidateQueries |
refetch | queryClient.refetchQueries |
cancel | queryClient.cancelQueries |
setData | queryClient.setQueryData |
getData | queryClient.getQueryData |
setInfiniteData | queryClient.setInfiniteQueryData |
getInfiniteData | queryClient.getInfiniteData |
❓ 必要な関数が見つかりません!
@tanstack/react-queryにはtRPCコンテキストにまだ実装されていない関数が多数あります。必要な関数が見つからない場合は、機能リクエストを投稿してください。
それまでの間は、@tanstack/react-queryから直接関数をインポートして使用できます。またフィルター適用時に適切なqueryKeyを取得するgetQueryKeyも提供しています。
プロキシクライアント
上記のreact-queryヘルパーに加え、コンテキストはtRPCプロキシクライアントも公開します。これにより追加のバニラクライアントを作成せずにasync/awaitでプロシージャを呼び出せます。
tsximport { trpc } from '../utils/trpc';function MyComponent() {const [apiKey, setApiKey] = useState();const utils = trpc.useUtils();return (<FormhandleSubmit={async (event) => {const apiKey = await utils.client.apiKey.create.mutate(event);setApiKey(apiKey);}}>...</Form>);}
tsximport { trpc } from '../utils/trpc';function MyComponent() {const [apiKey, setApiKey] = useState();const utils = trpc.useUtils();return (<FormhandleSubmit={async (event) => {const apiKey = await utils.client.apiKey.create.mutate(event);setApiKey(apiKey);}}>...</Form>);}
クエリの無効化
クエリの無効化はinvalidateヘルパーで行います。invalidateは他のヘルパーと異なり、ルーターマップの全レベルで利用可能という特別なヘルパーです。つまり単一クエリ、ルーター全体、あるいは全ルーターに対してinvalidateを実行できます。詳細は以下のセクションで説明します。
単一クエリの無効化
単一プロシージャに関連するクエリを無効化できます。さらに渡された入力に基づいてフィルタリングすることで、バックエンドへの不要な呼び出しを防止できます。
コード例
tsximport { trpc } from '../utils/trpc';function MyComponent() {const utils = trpc.useUtils();const mutation = trpc.post.edit.useMutation({onSuccess(input) {utils.post.all.invalidate();utils.post.byId.invalidate({ id: input.id }); // Will not invalidate queries for other id's 👍},});// [...]}
tsximport { trpc } from '../utils/trpc';function MyComponent() {const utils = trpc.useUtils();const mutation = trpc.post.edit.useMutation({onSuccess(input) {utils.post.all.invalidate();utils.post.byId.invalidate({ id: input.id }); // Will not invalidate queries for other id's 👍},});// [...]}
ルーター全体の無効化
ルーター全体の無効化
コード例
Backend code
server/routers/_app.tstsximport { initTRPC } from '@trpc/server';import { z } from 'zod';export const t = initTRPC.create();export const appRouter = t.router({// sub Post routerpost: t.router({all: t.procedure.query(() => {return {posts: [{ id: 1, title: 'everlong' },{ id: 2, title: 'After Dark' },],};}),byId: t.procedure.input(z.object({id: z.string(),}),).query(({ input }) => {return {post: { id: input?.id, title: 'Look me up!' },};}),edit: t.procedure.input(z.object({ id: z.number(), title: z.string() })).mutation(({ input }) => {return { post: { id: input.id, title: input.title } };}),}),// separate user routeruser: t.router({all: t.procedure.query(() => {return { users: [{ name: 'Dave Grohl' }, { name: 'Haruki Murakami' }] };}),}),});
server/routers/_app.tstsximport { initTRPC } from '@trpc/server';import { z } from 'zod';export const t = initTRPC.create();export const appRouter = t.router({// sub Post routerpost: t.router({all: t.procedure.query(() => {return {posts: [{ id: 1, title: 'everlong' },{ id: 2, title: 'After Dark' },],};}),byId: t.procedure.input(z.object({id: z.string(),}),).query(({ input }) => {return {post: { id: input?.id, title: 'Look me up!' },};}),edit: t.procedure.input(z.object({ id: z.number(), title: z.string() })).mutation(({ input }) => {return { post: { id: input.id, title: input.title } };}),}),// separate user routeruser: t.router({all: t.procedure.query(() => {return { users: [{ name: 'Dave Grohl' }, { name: 'Haruki Murakami' }] };}),}),});
tsximport { trpc } from '../utils/trpc';function MyComponent() {const utils = trpc.useUtils();const invalidateAllQueriesAcrossAllRouters = () => {// 1️⃣// All queries on all routers will be invalidated 🔥utils.invalidate();};const invalidateAllPostQueries = () => {// 2️⃣// All post queries will be invalidated 📭utils.post.invalidate();};const invalidatePostById = () => {// 3️⃣// All queries in the post router with input {id:1} invalidated 📭utils.post.byId.invalidate({ id: 1 });};// Example queriestrpc.user.all.useQuery(); // Would only be validated by 1️⃣ only.trpc.post.all.useQuery(); // Would be invalidated by 1️⃣ & 2️⃣trpc.post.byId.useQuery({ id: 1 }); // Would be invalidated by 1️⃣, 2️⃣ and 3️⃣trpc.post.byId.useQuery({ id: 2 }); // would be invalidated by 1️⃣ and 2️⃣ but NOT 3️⃣!// [...]}
tsximport { trpc } from '../utils/trpc';function MyComponent() {const utils = trpc.useUtils();const invalidateAllQueriesAcrossAllRouters = () => {// 1️⃣// All queries on all routers will be invalidated 🔥utils.invalidate();};const invalidateAllPostQueries = () => {// 2️⃣// All post queries will be invalidated 📭utils.post.invalidate();};const invalidatePostById = () => {// 3️⃣// All queries in the post router with input {id:1} invalidated 📭utils.post.byId.invalidate({ id: 1 });};// Example queriestrpc.user.all.useQuery(); // Would only be validated by 1️⃣ only.trpc.post.all.useQuery(); // Would be invalidated by 1️⃣ & 2️⃣trpc.post.byId.useQuery({ id: 1 }); // Would be invalidated by 1️⃣, 2️⃣ and 3️⃣trpc.post.byId.useQuery({ id: 2 }); // would be invalidated by 1️⃣ and 2️⃣ but NOT 3️⃣!// [...]}
全ミューテーションでのキャッシュ全体無効化
ミューテーションがどのクエリを無効化すべきか正確に追跡するのは困難です。そのため、あらゆるミューテーションの副作用として_キャッシュ全体_を無効化するのが現実的な解決策となる場合があります。リクエストバッチングがあるため、この無効化は閲覧中のページの全クエリを単一リクエストで再取得します。
これを支援する機能を追加しました:
tsexport const trpc = createTRPCReact<AppRouter, SSRContext>({overrides: {useMutation: {/*** This function is called whenever a `.useMutation` succeeds**/async onSuccess(opts) {/*** @note that order here matters:* The order here allows route changes in `onSuccess` without* having a flash of content change whilst redirecting.**/// Calls the `onSuccess` defined in the `useQuery()`-options:await opts.originalFn();// Invalidate all queries in the react-query cache:await opts.queryClient.invalidateQueries();},},},});
tsexport const trpc = createTRPCReact<AppRouter, SSRContext>({overrides: {useMutation: {/*** This function is called whenever a `.useMutation` succeeds**/async onSuccess(opts) {/*** @note that order here matters:* The order here allows route changes in `onSuccess` without* having a flash of content change whilst redirecting.**/// Calls the `onSuccess` defined in the `useQuery()`-options:await opts.originalFn();// Invalidate all queries in the react-query cache:await opts.queryClient.invalidateQueries();},},},});
追加オプション
クエリヘルパーに加え、useUtilsが返すオブジェクトには以下のプロパティも含まれます:
tsinterface ProxyTRPCContextProps<TRouter extends AnyRouter, TSSRContext> {/*** The `TRPCClient`*/client: TRPCClient<TRouter>;/*** The SSR context when server-side rendering* @default null*/ssrContext?: TSSRContext | null;/*** State of SSR hydration.* - `false` if not using SSR.* - `prepass` when doing a prepass to fetch queries' data* - `mounting` before TRPCProvider has been rendered on the client* - `mounted` when the TRPCProvider has been rendered on the client* @default false*/ssrState?: SSRState;/*** Abort loading query calls when unmounting a component - usually when navigating to a new page* @default false*/abortOnUnmount?: boolean;}
tsinterface ProxyTRPCContextProps<TRouter extends AnyRouter, TSSRContext> {/*** The `TRPCClient`*/client: TRPCClient<TRouter>;/*** The SSR context when server-side rendering* @default null*/ssrContext?: TSSRContext | null;/*** State of SSR hydration.* - `false` if not using SSR.* - `prepass` when doing a prepass to fetch queries' data* - `mounting` before TRPCProvider has been rendered on the client* - `mounted` when the TRPCProvider has been rendered on the client* @default false*/ssrState?: SSRState;/*** Abort loading query calls when unmounting a component - usually when navigating to a new page* @default false*/abortOnUnmount?: boolean;}