Saltar al contenido principal
Versión: 9.x

Uso con Next.js

Traducción Beta No Oficial

Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →

consejo

Si estás usando tRPC en un nuevo proyecto, considera utilizar uno de los proyectos de ejemplo como punto de partida o referencia: Proyectos de ejemplo de tRPC

¡tRPC y Next.js son una combinación perfecta! Next.js te permite construir tu cliente y servidor juntos en un mismo código base. Esto facilita compartir tipos entre ellos.

tRPC incluye herramientas dedicadas para que la experiencia de desarrollo con Next.js sea lo más fluida posible.

Estructura de archivos recomendada

Estructura de archivos recomendada pero no obligatoria. Esto es lo que obtendrás al comenzar con los ejemplos.

graphql
.
├── prisma # <-- if prisma is added
│ └── [..]
├── src
│ ├── pages
│ │ ├── _app.tsx # <-- add `withTRPC()`-HOC here
│ │ ├── api
│ │ │ └── trpc
│ │ │ └── [trpc].ts # <-- tRPC HTTP handler
│ │ └── [..]
│ ├── server
│ │ ├── routers
│ │ │ ├── app.ts # <-- main app router
│ │ │ ├── post.ts # <-- sub routers
│ │ │ └── [..]
│ │ ├── context.ts # <-- create app context
│ │ └── createRouter.ts # <-- router helper
│ └── utils
│ └── trpc.ts # <-- your typesafe tRPC hooks
└── [..]
graphql
.
├── prisma # <-- if prisma is added
│ └── [..]
├── src
│ ├── pages
│ │ ├── _app.tsx # <-- add `withTRPC()`-HOC here
│ │ ├── api
│ │ │ └── trpc
│ │ │ └── [trpc].ts # <-- tRPC HTTP handler
│ │ └── [..]
│ ├── server
│ │ ├── routers
│ │ │ ├── app.ts # <-- main app router
│ │ │ ├── post.ts # <-- sub routers
│ │ │ └── [..]
│ │ ├── context.ts # <-- create app context
│ │ └── createRouter.ts # <-- router helper
│ └── utils
│ └── trpc.ts # <-- your typesafe tRPC hooks
└── [..]

Agregar tRPC a un proyecto existente de Next.js

1. Instalar dependencias

bash
yarn add @trpc/client @trpc/server @trpc/react @trpc/next zod react-query@3
bash
yarn add @trpc/client @trpc/server @trpc/react @trpc/next zod react-query@3
  • React Query: @trpc/react proporciona un envoltorio ligero sobre @tanstack/react-query. Es necesario como dependencia peer.

  • Zod: la mayoría de los ejemplos usan Zod para validación de entradas y lo recomendamos encarecidamente, aunque no es obligatorio. Puedes usar una biblioteca de validación de tu elección (Yup, Superstruct, io-ts, etc). De hecho, cualquier objeto que contenga un método parse, create o validateSync funcionará.

2. Habilitar modo estricto

Si quieres usar Zod para validación de entradas, asegúrate de habilitar el modo estricto en tu tsconfig.json:

json
// tsconfig.json
{
// ...
"compilerOptions": {
// ...
"strict": true
}
}
json
// tsconfig.json
{
// ...
"compilerOptions": {
// ...
"strict": true
}
}

Si el modo estricto es demasiado, al menos habilita strictNullChecks:

json
// tsconfig.json
{
// ...
"compilerOptions": {
// ...
"strictNullChecks": true
}
}
json
// tsconfig.json
{
// ...
"compilerOptions": {
// ...
"strictNullChecks": true
}
}

3. Crear un enrutador tRPC

Implementa tu enrutador tRPC en ./pages/api/trpc/[trpc].ts. Si necesitas dividir tu enrutador en varios subenrutadores, impleméntalos en un directorio server de nivel superior en la raíz de tu proyecto, luego impórtalos en ./pages/api/trpc/[trpc].ts y fusiónalos en un único appRouter raíz.

View sample router
./pages/api/trpc/[trpc].ts
ts
import * as trpc from '@trpc/server';
import * as trpcNext from '@trpc/server/adapters/next';
import { z } from 'zod';
export const appRouter = trpc.router().query('hello', {
input: z
.object({
text: z.string().nullish(),
})
.nullish(),
resolve({ input }) {
return {
greeting: `hello ${input?.text ?? 'world'}`,
};
},
});
// export type definition of API
export type AppRouter = typeof appRouter;
// export API handler
export default trpcNext.createNextApiHandler({
router: appRouter,
createContext: () => null,
});
./pages/api/trpc/[trpc].ts
ts
import * as trpc from '@trpc/server';
import * as trpcNext from '@trpc/server/adapters/next';
import { z } from 'zod';
export const appRouter = trpc.router().query('hello', {
input: z
.object({
text: z.string().nullish(),
})
.nullish(),
resolve({ input }) {
return {
greeting: `hello ${input?.text ?? 'world'}`,
};
},
});
// export type definition of API
export type AppRouter = typeof appRouter;
// export API handler
export default trpcNext.createNextApiHandler({
router: appRouter,
createContext: () => null,
});

4. Crear hooks tRPC

Crea un conjunto de hooks fuertemente tipados usando la firma de tipos de tu API.

utils/trpc.ts
tsx
import { createReactQueryHooks } from '@trpc/react';
import type { AppRouter } from '../pages/api/trpc/[trpc]';
export const trpc = createReactQueryHooks<AppRouter>();
// => { useQuery: ..., useMutation: ...}
utils/trpc.ts
tsx
import { createReactQueryHooks } from '@trpc/react';
import type { AppRouter } from '../pages/api/trpc/[trpc]';
export const trpc = createReactQueryHooks<AppRouter>();
// => { useQuery: ..., useMutation: ...}

5. Configurar _app.tsx

La función createReactQueryHooks espera ciertos parámetros pasados mediante la Context API. Para establecer estos parámetros, crea un _app.tsx personalizado usando el componente de orden superior withTRPC:

pages/_app.tsx
tsx
import { withTRPC } from '@trpc/next';
import { AppType } from 'next/dist/shared/lib/utils';
import type { AppRouter } from './api/trpc/[trpc]';
const MyApp: AppType = ({ Component, pageProps }) => {
return <Component {...pageProps} />;
};
export default withTRPC<AppRouter>({
config(config) {
/**
* If you want to use SSR, you need to use the server's full URL
* @see https://trpc.io/docs/ssr
*/
const url = process.env.VERCEL_URL
? `https://${process.env.VERCEL_URL}/api/trpc`
: 'http://localhost:3000/api/trpc';
return {
url,
/**
* @see https://tanstack.com/query/v3/docs/react/reference/QueryClient
*/
// queryClientConfig: { defaultOptions: { queries: { staleTime: 60 } } },
};
},
/**
* @see https://trpc.io/docs/ssr
*/
ssr: true,
})(MyApp);
pages/_app.tsx
tsx
import { withTRPC } from '@trpc/next';
import { AppType } from 'next/dist/shared/lib/utils';
import type { AppRouter } from './api/trpc/[trpc]';
const MyApp: AppType = ({ Component, pageProps }) => {
return <Component {...pageProps} />;
};
export default withTRPC<AppRouter>({
config(config) {
/**
* If you want to use SSR, you need to use the server's full URL
* @see https://trpc.io/docs/ssr
*/
const url = process.env.VERCEL_URL
? `https://${process.env.VERCEL_URL}/api/trpc`
: 'http://localhost:3000/api/trpc';
return {
url,
/**
* @see https://tanstack.com/query/v3/docs/react/reference/QueryClient
*/
// queryClientConfig: { defaultOptions: { queries: { staleTime: 60 } } },
};
},
/**
* @see https://trpc.io/docs/ssr
*/
ssr: true,
})(MyApp);

6. Realizar solicitudes a la API

pages/index.tsx
tsx
import { trpc } from '../utils/trpc';
export default function IndexPage() {
const hello = trpc.useQuery(['hello', { text: 'client' }]);
if (!hello.data) {
return <div>Loading...</div>;
}
return (
<div>
<p>{hello.data.greeting}</p>
</div>
);
}
pages/index.tsx
tsx
import { trpc } from '../utils/trpc';
export default function IndexPage() {
const hello = trpc.useQuery(['hello', { text: 'client' }]);
if (!hello.data) {
return <div>Loading...</div>;
}
return (
<div>
<p>{hello.data.greeting}</p>
</div>
);
}

Opciones de withTRPC()

Callback config

El argumento config es una función que devuelve un objeto que configura los clientes de tRPC y React Query. Esta función tiene una entrada ctx que te da acceso al objeto req de Next.js, entre otras cosas. El valor devuelto puede contener las siguientes propiedades:

  • Exactamente uno de estos es obligatorio:

    • url: tu URL de la API.
    • links: para personalizar el flujo de datos entre el cliente tRPC y el servidor tRPC. Leer más.
  • Opcionales:

    • queryClientConfig: objeto de configuración para el QueryClient de React Query usado internamente por los hooks React de tRPC: Documentación de QueryClient
    • headers: objeto o función que devuelve un objeto de solicitudes salientes tRPC
    • transformer: transformador aplicado a las cargas útiles salientes. Más información sobre Transformadores de datos
    • fetch: personaliza la implementación de fetch usada internamente por tRPC
    • AbortController: personaliza la implementación de AbortController usada internamente por tRPC

ssr-booleano (predeterminado: false)

Indica si tRPC debe esperar las consultas al renderizar una página en el servidor. Por defecto es false.

responseMeta-callback

Permite establecer encabezados de solicitud y estado HTTP durante el renderizado en el servidor.

Ejemplo

pages/_app.tsx
tsx
export default withTRPC<AppRouter>({
config(config) {
/* [...] */
},
ssr: true,
responseMeta({ clientErrors, ctx }) {
if (clientErrors.length) {
// propagate first http error from API calls
return {
status: clientErrors[0].data?.httpStatus ?? 500,
};
}
// cache full page for 1 day + revalidate once every second
const ONE_DAY_IN_SECONDS = 60 * 60 * 24;
return {
'Cache-Control': `s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`,
};
},
})(MyApp);
pages/_app.tsx
tsx
export default withTRPC<AppRouter>({
config(config) {
/* [...] */
},
ssr: true,
responseMeta({ clientErrors, ctx }) {
if (clientErrors.length) {
// propagate first http error from API calls
return {
status: clientErrors[0].data?.httpStatus ?? 500,
};
}
// cache full page for 1 day + revalidate once every second
const ONE_DAY_IN_SECONDS = 60 * 60 * 24;
return {
'Cache-Control': `s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`,
};
},
})(MyApp);

Próximos pasos

Consulta la documentación de @trpc/react para información adicional sobre cómo ejecutar Consultas y Mutaciones dentro de tus componentes.