Obtención de datos en Componentes de Servidor
Obtén datos directamente dentro de Componentes de Servidor asincronos con almacenamiento en caché y deduplicación incorporados.
Busca en todas las páginas de la documentación
Obtén datos directamente dentro de Componentes de Servidor asincronos con almacenamiento en caché y deduplicación incorporados.
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
Tarjeta de referencia rápida -- lista para copiar y pegar.
// app/posts/page.tsx (Server Component -- el predeterminado)
export default async function PostsPage() {
// Almacenado en caché por defecto (force-cache)
const res = await fetch("https://api.example.com/posts");
const posts: Post[] = await res.json();
return (
<ul>
{posts.map((p) => (
<li key={p.id}>{p.title}</li>
))}
</ul>
);
}
// Revalidación basada en tiempo
await fetch(url, { next: { revalidate: 60 } });
// Sin almacenamiento en caché -- siempre fresco
await fetch(url, { cache: "no-store" });
// Revalidación basada en etiquetas
await fetch(url, { next: { tags: ["posts"] } });Cuándo usarlo: Necesitas cargar datos para una página o componente que no tiene interactividad -- sin useState, sin onClick, sin APIs del navegador.
// lib/api.ts
export type Post = { id: number; title: string; body: string };
export async function getPosts(): Promise<Post[]> {
const res = await fetch("https://jsonplaceholder.typicode.com/posts", {
next: { revalidate: 300, tags: ["posts"] },
});
if (!res.ok) throw new Error("Failed to fetch posts");
return res.json();
}
export async function getPost(id: number): Promise<Post> {
const res = await fetch(
`https://jsonplaceholder.typicode.com/posts/${id}`,
{ next: { tags: [`post-${id}`] } }
);
if (!res.ok) throw new Error(`Post ${id} not found`);
return res.json();
}// app/posts/page.tsx
import { getPosts } from "@/lib/api";
import Link from "next/link";
export default async function PostsPage() {
const posts = await getPosts();
return (
<main className="max-w-2xl mx-auto p-6">
<h1 className="text-2xl font-bold mb-4">Posts</h1>
<ul className="space-y-2">
{posts.slice(0, 10).map((post) => (
<li key={post.id}>
<Link
href={`/posts/${post.id}`}
className="text-blue-600 hover:underline"
>
{post.title}
</Link>
</li>
))}
</ul>
</main>
);
}// app/posts/[id]/page.tsx
import { getPost } from "@/lib/api";
import { notFound } from "next/navigation";
type Props = { params: Promise<{ id: string }> };
export default async function PostPage({ params }: Props) {
const { id } = await params;
const numericId = Number(id);
if (Number.isNaN(numericId)) notFound();
const post = await getPost(numericId);
return (
<article className="max-w-2xl mx-auto p-6">
<h1 className="text-3xl font-bold mb-2">{post.title}</h1>
<p className="text-gray-700 leading-relaxed">{post.body}</p>
</article>
);
}Lo que esto demuestra:
useEffect, sin estado de carga del lado del clientelib/ para reutilización entre componentesnext.revalidate para ISR basado en tiempo y next.tags para revalidación bajo demandaparams de ruta dinámica como una Promise (patrón de Next.js 15+)async y llamar await fetch() directamente en el cuerpo de la función.fetch con opciones cache y next. El comportamiento predeterminado en Next.js 15+ es cache: "auto", que permite que el framework decida según el contexto.error.tsx más cercano.Obtención de datos en paralelo (evitar cascadas):
export default async function DashboardPage() {
// Inicia ambos fetches simultáneamente
const [users, orders] = await Promise.all([
fetch("https://api.example.com/users").then((r) => r.json()),
fetch("https://api.example.com/orders").then((r) => r.json()),
]);
return (
<>
<UserTable users={users} />
<OrderList orders={orders} />
</>
);
}Fuentes de datos que no son fetch (base de datos, ORM):
import { cache } from "react";
import { db } from "@/lib/db";
// Envuelve con React.cache para memoización a nivel de solicitud
export const getUser = cache(async (id: string) => {
return db.user.findUnique({ where: { id } });
});Pasar una promesa a un Componente de Cliente:
// Componente de Servidor
export default async function Page() {
const dataPromise = fetchSlowData(); // NO hagas await
return <ClientChart dataPromise={dataPromise} />;
}// Siempre tipifica tus respuestas de fetch
type ApiResponse<T> = { data: T; total: number };
async function getItems(): Promise<ApiResponse<Item[]>> {
const res = await fetch("/api/items");
return res.json();
}
// params es una Promise en Next.js 15+
type PageProps = {
params: Promise<{ slug: string }>;
searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
};Cascadas de fetch -- Las llamadas await secuenciales crean cascadas donde cada fetch espera al anterior. Solución: Usa Promise.all() para solicitudes independientes o mueve cada fetch a su propio componente envuelto con Suspense para streaming en paralelo.
Olvidar manejo de errores -- Un error de fetch no detectado bloquea toda la ruta. Solución: Lanza un error desde tu asistente de fetch para que el límite error.tsx más cercano lo capture, o usa try/catch para manejo granular.
cache: "no-store" hace que toda la ruta sea dinámica -- Si cualquier fetch en una ruta usa no-store, toda la ruta optar out de la generación estática. Solución: Aísla los fetches dinámicos en componentes separados envueltos con Suspense para que el resto de la ruta pueda permanecer estático.
Las llamadas sin fetch no se deduplicarán automáticamente -- Las consultas directas a bases de datos o llamadas de SDK de terceros omiten la memoización de solicitud de React. Solución: Envuélvelas con React.cache() para obtener deduplicación por solicitud.
params y searchParams son Promises en Next.js 15+ -- Desestructurarlos directamente sin await te da un objeto Promise, no los valores. Solución: Siempre await params y await searchParams antes de acceder a las propiedades.
| Alternativa | Úsalo Cuando | No lo uses Cuando |
|---|---|---|
| Route Handlers (rutas API) | Necesitas un endpoint REST independiente para consumidores externos | Solo necesitas datos dentro de un Componente de Servidor |
| SWR o React Query en el cliente | Necesitas actualizaciones en tiempo real, polling, o mutaciones optimistas | Los datos pueden obtenerse una vez en el servidor |
| Server Actions | Necesitas mutar datos, no leerlos | Solo necesitas solicitudes GET |
React.cache + ORM | Obttienes datos de una base de datos, no de una API HTTP | Estás llamando a una API REST pública |
unstable_cache (Next.js) | Necesitas semántica de Data Cache para fuentes de datos que no son fetch | Plain fetch con next.revalidate ya funciona |
useEffect o librerías como SWR para obtención asincronida de datos en Componentes de Clientecache: "no-store" omite completamente el Data Cacherevalidate: 0 también omite almacenamiento en caché pero señala intención a través de la API de ISRReact.cache() para fuentes de datos que no son fetch como consultas directas a bases de datos o llamadas ORMfetchReact.cache() proporciona memoización por solicitud para cualquier función asincronía// Next.js 15+: params es una Promise
type Props = { params: Promise<{ id: string }> };
export default async function Page({ params }: Props) {
const { id } = await params;
// usa id
}"[object Promise]"await params antes de acceder a las propiedades// Usa Promise.all para ejecutar fetches en paralelo
const [users, orders] = await Promise.all([
fetch("/api/users").then((r) => r.json()),
fetch("/api/orders").then((r) => r.json()),
]);<Suspense>type ApiResponse<T> = { data: T; total: number };
async function getItems(): Promise<ApiResponse<Item[]>> {
const res = await fetch("/api/items");
if (!res.ok) throw new Error("Failed to fetch");
return res.json();
}cache: "auto", que permite que el framework decida según el contextoforce-cachecache o next.revalidate en cada llamada de fetch// Componente de Servidor: pasa la promesa, no el valor resuelto
export default async function Page() {
const dataPromise = fetchSlowData(); // NO hagas await
return <ClientChart dataPromise={dataPromise} />;
}use() de Reacterror.tsx más cercano lo captura si existe unoRevisado por Chris St. John·Última actualización: 19 jul 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥