/
githubmirror
/
trpc
Обзор
Документация
Войти
/
githubmirror
/
trpc
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
www/docs/client/react/useUtils.mdx
411 строк
14 KB
Nick Lucas
feat(docs): revamp docs content for 2026, more framework agnostic, improved Next.js docs (#7193)
08 мар 2026, 12:14
Не верифицирован
08 мар 2026, 12:14
2bf122d
Код
Авторство
О чём код?
--- id: useUtils title: useUtils sidebar_label: useUtils() slug: /client/react/useUtils --- `useUtils` is a hook that gives you access to helpers that let you manage the cached data of the queries you execute via `@trpc/react-query`. These helpers are actually thin wrappers around `@tanstack/react-query`'s [`queryClient`](https://tanstack.com/query/v5/docs/reference/QueryClient) methods. If you want more in-depth information about options and usage patterns for `useUtils` helpers than what we provide here, we will link to their respective `@tanstack/react-query` docs so you can refer to them accordingly. :::note This hook was called `useContext()` until `10.41.0` (and is still aliased for the foreseeable future) ::: ## Usage `useUtils` returns an object with all the available queries you have in your routers. You use it the same way as your `trpc` client object. Once you reach a query, you'll have access to the query helpers. For example, let's say you have a `post` router with an `all` query: ```twoslash include server // @target: esnext // @filename: server.ts import { initTRPC } from '@trpc/server'; import { z } from 'zod'; const t = initTRPC.create(); const appRouter = t.router({ post: t.router({ all: t.procedure.query(() => { return { posts: [ { id: 1, title: 'everlong' }, { id: 2, title: 'After Dark' }, ], }; }), }), }); export type AppRouter = typeof appRouter; ``` ```ts twoslash title='server.ts' // @target: esnext // @filename: server.ts // ---cut--- import { initTRPC } from '@trpc/server'; import { z } from 'zod'; const t = initTRPC.create(); const appRouter = t.router({ post: t.router({ all: t.procedure.query(() => { return { posts: [ { id: 1, title: 'everlong' }, { id: 2, title: 'After Dark' }, ], }; }), }), }); export type AppRouter = typeof appRouter; ``` Now in our component, when we navigate the object `useUtils` gives us and reach the `post.all` query, we'll get access to our query helpers! ```tsx twoslash title="MyComponent.tsx" // @target: esnext // @include: server // @filename: MyComponent.tsx // ---cut--- // @errors: 2339 import { createTRPCReact } from '@trpc/react-query'; import type { AppRouter } from './server'; const trpc = createTRPCReact<AppRouter>(); function MyComponent() { const utils = trpc.useUtils(); utils.post.all.f; // ^| } ``` ## Helpers These are the helpers you'll get access to via `useUtils`. The table below will help you know which tRPC helper wraps which `@tanstack/react-query` helper method. Each react-query method will link to its respective docs/guide: | tRPC helper wrapper | `@tanstack/react-query` helper method | | --------------------- | -------------------------------------------------------------------------------------------------------------------------------- | | `fetch` | [`queryClient.fetchQuery`](https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientfetchquery) | | `prefetch` | [`queryClient.prefetchQuery`](https://tanstack.com/query/v5/docs/framework/react/guides/prefetching) | | `fetchInfinite` | [`queryClient.fetchInfiniteQuery`](https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientfetchinfinitequery) | | `prefetchInfinite` | [`queryClient.prefetchInfiniteQuery`](https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientprefetchinfinitequery) | | `ensureData` | [`queryClient.ensureData`](https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientensurequerydata) | | `invalidate` | [`queryClient.invalidateQueries`](https://tanstack.com/query/v5/docs/framework/react/guides/query-invalidation) | | `refetch` | [`queryClient.refetchQueries`](https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientrefetchqueries) | | `cancel` | [`queryClient.cancelQueries`](https://tanstack.com/query/v5/docs/framework/react/guides/query-cancellation) | | `setData` | [`queryClient.setQueryData`](https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientsetquerydata) | | `setQueriesData` | [`queryClient.setQueriesData`](https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientsetqueriesdata) | | `getData` | [`queryClient.getQueryData`](https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientgetquerydata) | | `setInfiniteData` | [`queryClient.setInfiniteQueryData`](https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientsetquerydata) | | `getInfiniteData` | [`queryClient.getInfiniteData`](https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientgetquerydata) | | `setMutationDefaults` | [`queryClient.setMutationDefaults`](https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientsetmutationdefaults) | | `getMutationDefaults` | [`queryClient.getMutationDefaults`](https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientgetmutationdefaults) | | `isMutating` | [`queryClient.isMutating`](https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientismutating) | | `reset` | [`queryClient.resetQueries`](https://tanstack.com/query/v5/docs/reference/QueryClient#queryclientresetqueries) | ### ❓ The function I want isn't here! `@tanstack/react-query` has a lot of functions that we haven't put in the tRPC context yet. If you need a function that isn't here, feel free to [open a feature request](https://github.com/trpc/trpc/issues/new/choose) requesting it. In the meantime, you can import and use the function directly from `@tanstack/react-query`. We also provide a [getQueryKey](/docs/client/react/getQueryKey) which you can use to get the correct queryKey on the filters when using these functions. ## Proxy client In addition to the above react-query helpers, the context also exposes your tRPC proxy client. This lets you call your procedures with `async`/`await` without needing to create an additional vanilla client. ```tsx twoslash // @jsx: react-jsx // @filename: server.ts import { initTRPC } from '@trpc/server'; const t = initTRPC.create(); export const appRouter = t.router({ apiKey: t.router({ create: t.procedure.mutation(() => 'new-api-key'), }), }); export type AppRouter = typeof appRouter; // @filename: utils/trpc.tsx import { createTRPCReact } from '@trpc/react-query'; import type { AppRouter } from '../server'; export const trpc = createTRPCReact<AppRouter>(); // @filename: MyComponent.tsx // ---cut--- import { useState } from 'react'; import { trpc } from './utils/trpc'; function MyComponent() { const [apiKey, setApiKey] = useState(''); const utils = trpc.useUtils(); return ( <form onSubmit={async (event) => { const apiKey = await utils.client.apiKey.create.mutate(); setApiKey(apiKey); }} > {/* form content */} </form> ); } ``` ## Query Invalidation You invalidate queries via the `invalidate` helper. `invalidate` is actually a special helper given that, unlike the other helpers, it's available at every level of the router map. This means you can either run `invalidate` on a single query, a whole router, or every router if you want. We get more in detail in the sections below. ### Invalidating a single query You can invalidate a query relating to a single procedure and even filter based on the input passed to it to prevent unnecessary calls to the back end. #### Example code ```tsx twoslash // @target: esnext // @filename: server.ts import { initTRPC } from '@trpc/server'; import { z } from 'zod'; const t = initTRPC.create(); const appRouter = t.router({ post: t.router({ all: t.procedure.query(() => { return { posts: [{ id: 1, title: 'everlong' }] }; }), byId: t.procedure .input(z.object({ id: z.number() })) .query(({ input }) => ({ post: { id: input.id, title: 'Look me up!' } })), edit: t.procedure .input(z.object({ id: z.number(), title: z.string() })) .mutation(({ input }) => ({ id: input.id, title: input.title })), }), }); export type AppRouter = typeof appRouter; // @filename: utils/trpc.tsx import { createTRPCReact } from '@trpc/react-query'; import type { AppRouter } from '../server'; export const trpc = createTRPCReact<AppRouter>(); // @filename: MyComponent.tsx // ---cut--- import { 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 }, }); // [...] } ``` ### Invalidating across whole routers It is also possible to invalidate queries across an entire router rather than just one query. #### Example code <details> <summary>Backend code</summary> ```tsx twoslash title='server/routers/_app.ts' import { initTRPC } from '@trpc/server'; import { z } from 'zod'; export const t = initTRPC.create(); export const appRouter = t.router({ // sub Post router post: 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 router user: t.router({ all: t.procedure.query(() => { return { users: [{ name: 'Dave Grohl' }, { name: 'Haruki Murakami' }] }; }), }), }); ``` </details> ```tsx twoslash // @target: esnext // @filename: server.ts import { initTRPC } from '@trpc/server'; import { z } from 'zod'; const t = initTRPC.create(); const appRouter = t.router({ post: t.router({ all: t.procedure.query(() => ({ posts: [{ id: 1, title: 'everlong' }, { id: 2, title: 'After Dark' }], })), byId: t.procedure .input(z.object({ id: z.number() })) .query(({ input }) => ({ post: { id: input.id, title: 'Look me up!' } })), edit: t.procedure .input(z.object({ id: z.number(), title: z.string() })) .mutation(({ input }) => ({ post: { id: input.id, title: input.title } })), }), user: t.router({ all: t.procedure.query(() => ({ users: [{ name: 'Dave Grohl' }, { name: 'Haruki Murakami' }], })), }), }); export type AppRouter = typeof appRouter; // @filename: utils/trpc.tsx import { createTRPCReact } from '@trpc/react-query'; import type { AppRouter } from '../server'; export const trpc = createTRPCReact<AppRouter>(); // @filename: MyComponent.tsx // ---cut--- import { 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 queries trpc.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️⃣! // [...] } ``` ### Invalidate full cache on every mutation Keeping track of exactly what queries a mutation should invalidate is hard, therefore, it can be a pragmatic solution to invalidate the _full cache_ as a side-effect on any mutation. Since we have request batching, this invalidation will simply refetch all queries on the page you're looking at in one single request. We have added a feature to help with this: ```ts twoslash // @target: esnext // @include: server // @filename: utils/trpc.ts // ---cut--- import { createTRPCReact } from '@trpc/react-query'; import type { AppRouter } from '../server'; export const trpc = createTRPCReact<AppRouter>({ 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(); }, }, }, }); ``` ## Additional Options Aside from the query helpers, the object `useUtils` returns also contains the following properties: ```ts twoslash type AnyRouter = any; type TRPCClient<T> = any; type SSRState = false | 'prepass' | 'mounting' | 'mounted'; // ---cut--- interface 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; } ```