tRPCMiddleTechnical

Что такое клиент createTRPCReact и как он интегрируется с React Query?

createTRPCReact создаёт типизированный набор React-хуков (useQuery, useMutation и др.), которые под капотом делегируют вызовы React Query, сохраняя полную end-to-end типизацию процедур сервера.

Что такое createTRPCReact

createTRPCReact — фабрика из пакета @trpc/react-query, которая принимает тип вашего AppRouter и возвращает объект trpc с проксированными хуками. Каждый хук (например, trpc.user.getById.useQuery()) — это тонкая обёртка над соответствующим хуком React Query (useQuery, useMutation, useInfiniteQuery), но со статически выведенными типами входных и выходных данных.

Как это работает внутри

При вызове trpc.user.getById.useQuery({ id: 1 }) tRPC:

  • Формирует уникальный queryKey вида [['user', 'getById'], { input: { id: 1 }, type: 'query' }].
  • Создаёт queryFn, которая отправляет HTTP-запрос (GET по умолчанию для query, POST для mutation) через настроенный httpBatchLink или другой link.
  • Передаёт всё это в стандартный useQuery из @tanstack/react-query.

Таким образом, весь кэш, инвалидация, дедупликация и фоновые рефетчи остаются в зоне ответственности React Query — tRPC только добавляет типизацию и сериализацию.

Минимальная интеграция

// lib/trpc.ts
import { createTRPCReact } from '@trpc/react-query';
import type { AppRouter } from '../server/router';

export const trpc = createTRPCReact<AppRouter>();
// app/providers.tsx
'use client';
import { useState } from 'react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { httpBatchLink } from '@trpc/client';
import { trpc } from '../lib/trpc';

export function Providers({ children }: { children: React.ReactNode }) {
  const [queryClient] = useState(() => new QueryClient());
  const [trpcClient] = useState(() =>
    trpc.createClient({
      links: [
        httpBatchLink({
          url: '/api/trpc',
        }),
      ],
    })
  );

  return (
    <trpc.Provider client={trpcClient} queryClient={queryClient}>
      <QueryClientProvider client={queryClient}>
        {children}
      </QueryClientProvider>
    </trpc.Provider>
  );
}
// components/UserCard.tsx
'use client';
import { trpc } from '../lib/trpc';

export function UserCard({ id }: { id: number }) {
  const { data, isLoading, error } = trpc.user.getById.useQuery({ id });

  if (isLoading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;

  return <div>{data?.name}</div>;
}

Доступ к нативным опциям React Query

Все опции useQuery и useMutation из React Query передаются вторым аргументом без изменений:

const { data } = trpc.posts.list.useQuery(
  { limit: 10 },
  {
    staleTime: 60_000,
    refetchOnWindowFocus: false,
    select: (d) => d.items,
  }
);

Подводные камни

  • Два экземпляра QueryClient. Если создать QueryClient вне useState, при HMR в Next.js он пересоздаётся и кэш сбрасывается.
  • trpc.Provider и QueryClientProvider должны получать один и тот же экземпляр queryClient. Если передать разные, мутации и инвалидация перестанут работать корректно.
  • queryKey генерируется автоматически и включает сериализованный input. Любое изменение структуры input-объекта — это новый ключ, что может вызвать лишние запросы.
  • Серверные компоненты (RSC) несовместимы с хуками tRPC — в RSC нужно использовать createCaller или прямые вызовы процедур на сервере.
  • Версия @tanstack/react-query должна совпадать с той, что ожидает @trpc/react-query. Конфликты peer deps — частая причина ошибок runtime.
  • Batching объединяет запросы за один тик. Если компонент делает несколько useQuery, они попадут в один HTTP-запрос, что хорошо для производительности, но затрудняет отладку в DevTools.

Common mistakes

  • Смешивать «createTRPCReact» с похожим механизмом без критерия выбора.
  • Игнорировать риск: неверно оценить границы применения темы «createTRPCReact» и получить хрупкое решение.
  • Показывать только синтаксис и не объяснять поведение в runtime или сборке.

What the interviewer is testing

  • Объясняет React hooks wrapper поверх tRPC client и TanStack React Query.
  • Показывает на примере, как работает: createTRPCReact<AppRouter>() генерирует typed hooks для процедур, а кэширование, retries, invalidation и stale state делегируются React Query.
  • Называет production-нюанс и граничный случай для темы «createTRPCReact».

Sources

Related topics