# useUtils

> Invalidate, refetch, prefetch and update cached query data with the classic trpc.useUtils() helpers

> [!WARNING] Deprecated
> The classic React Query integration (`@trpc/react-query`) only gets bug fixes, and will be removed in the next major version of tRPC. New projects should use the [TanStack React Query integration](https://trpc.io/docs/client/tanstack-react-query.md) (`@trpc/tanstack-react-query`). To move an existing project, follow the [migration guide](https://trpc.io/docs/client/tanstack-react-query/migrating.md).


`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:

```ts title="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;
```

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 title="MyComponent.tsx"
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](https://trpc.io/docs/client/react/getQueryKey.md) 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
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
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 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
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
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
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;
}
```
