Explicación de la pre-renderización parcial y la renderización concurrente
Aprenda cómo el preprocesamiento parcial de Next.js y el renderizado concurrente de React solucionan los problemas de lentitud en las aplicaciones al permitir que los frameworks programen y ejecuten tareas de forma secuencial, en lugar de tratar los procesos de renderizado como una sola unidad que bloquea todo.
El trabajo de mejora del rendimiento en React y Next.js siempre vuelve al mismo principio: forzar que toda una página o todo un proceso de renderizado funcione como una sola unidad continua es lo que hace que las aplicaciones parezcan lentas. Dos técnicas abordan este problema desde ángulos diferentes: el pre-renderizado parcial, que permite a una única ruta de Next.js combinar contenido estático y dinámico, y el renderizado concurrente, que permite a React interrumpir y reorganizar las tareas dentro del navegador. Juntos, muestran un patrón que vale la pena comprender: las mejoras en el rendimiento provienen cada vez menos de escribir código “más rápido”, y más bien de permitir que el framework planifique y ejecute las tareas de manera más inteligente.
La antigua opción de renderizado todo-o-nada
Durante mucho tiempo, una página de Next.js solo tenía exactamente dos modos de renderizado entre los que elegir:
- Generación estática (SSG) — las páginas se sirven rápidamente porque se crean con antelación, pero el contenido se vuelve obsoleto hasta la siguiente reconstrucción.
- Renderizado del lado del servidor (SSR) — el contenido siempre está actualizado, pero cada solicitud debe esperar al dato más lento antes de que se envíe cualquier cosa.
El problema es que la mayoría de las páginas reales no encajan perfectamente en ninguno de estos dos enfoques. Una página de producto, por ejemplo, es en su mayor parte estática: el diseño, la navegación y el texto de marketing no cambian con cada solicitud; pero también contiene algunos elementos verdaderamente dinámicos, como un indicador de carrito o un contador de existencias en tiempo real. Renderizar toda la página mediante SSR solo para mantener actualizado un pequeño widget implica pagar el costo completo de renderización del servidor por contenido que no lo necesitaba.
Permitir que una ruta sea tanto estática como dinámica
El Pre-renderizado Parcial (PPR) existe para cerrar esa brecha. Permite que una única ruta envíe inmediatamente una estructura estática, mientras que los fragmentos dinámicos dentro de ella se transmiten en cuanto se obtienen sus datos: sin páginas separadas y sin tener que alternar entre getStaticProps y getServerSideProps.
// app/product/[id]/page.tsx
import { Suspense } from 'react';
import ProductShell from '@/components/ProductShell';
import LiveInventory from '@/components/LiveInventory';
export default function ProductPage({ params }: { params: { id: string } }) {
return (
<ProductShell productId={params.id}>
{/* static instantly, no waiting on the network */}
<Suspense fallback={<InventorySkeleton />}>
{/* streamed in once the dynamic data resolves */}
<LiveInventory productId={params.id} />
</Suspense>
</ProductShell>
);
}
El mecanismo es un límite Suspense. Todo lo que se coloca fuera de él se pre-renderiza en el momento de la compilación y se sirve al instante; todo lo que está dentro de él se calcula y transmite en el momento de la solicitud. Ese es todo el modelo mental: un archivo, una ruta, dos estrategias de renderizado que coexisten.
Esta división genera varios beneficios concretos. La velocidad para recibir el primer byte mejora porque la capa estática proviene directamente del servidor sin tener que calcularse para cada solicitud. Tampoco hay necesidad de un estado de carga de página completa: los visitantes ven de inmediato las partes estáticas y relevantes de la página, mientras que las secciones dinámicas más pequeñas se cargan a medida que se procesan. Además, la carga mental es menor que al mantener páginas estáticas y generadas por servidor separadas, ya que se trabaja con una única ruta y un único archivo que combina simplemente distintas estrategias. El equipo de Next.js describe este objetivo como ofrecer las ventajas tanto del renderizado estático como del dinámico, sin los habituales compromisos arquitectónicos.
Algunas pautas prácticas hacen que PPR sea eficaz en la producción. Mantenga los límites de Suspense ajustados únicamente alrededor de las partes que son realmente dinámicas; incluir demasiado contenido anula el propósito de prerender nada en absoluto. Mantenga los esqueletos de respaldo ligeros, ya que esos respaldos forman parte del shell renderizado estáticamente. Si utiliza TypeScript, defina contratos claros de propiedades entre el shell estático y los componentes cargados dinámicamente para que ambos se mantengan sincronizados a medida que evolucionan. Y al probar, reduzca la velocidad de su conexión a algo similar a una 3G lenta en las herramientas de desarrollo del navegador: las ventajas de PPR se vuelven mucho más evidentes en condiciones de red realistas que con una conexión local rápida.
Si su equipo utiliza Next.js 14 o una versión posterior, vale la pena probar el PPR en una única ruta antes de adoptarlo en toda la aplicación. No se trata de un término de marketing; es una estrategia de renderizado que finalmente coincide con el comportamiento real de las páginas: en parte estáticas, en parte dinámicas, al mismo tiempo.
Ampliando la misma idea al renderizado del lado del cliente
El Pre-renderizado parcial resuelve la división entre contenido estático y dinámico a nivel del servidor y de la red. El Renderizado concurrente, introducido con React 18 y perfeccionado aún más en React 19, resuelve un problema similar dentro del navegador: en lugar de elegir entre “renderizar todo ahora” o “no renderizar nada por el momento”, React puede renderizar algunas cosas de inmediato y dejar que otras esperen.
Antes de React 18, el renderizado era síncrono y bloqueante. Una sola actualización de estado desencadenaba un nuevo renderizado que se completaba sin importar nada más, incluso si eso significaba congelar el desplazamiento o las entradas mientras React procesaba todo el árbol.
El renderizado concurrente cambia ese comportamiento. Ahora React puede pausar un renderizado a mitad de proceso, dar prioridad a actualizaciones urgentes como la escritura o los clics sobre aquellas no urgentes como filtrar una lista larga, y descartar el trabajo en curso si una actualización más reciente lo hace irrelevante. Lo importante es que no se trata de una nueva API que deba aprenderse desde cero, sino de un modelo de programación diferente que opera detrás de los hooks que ya utiliza.
Los hooks que exponen la programación concurrente
useTransition le permite marcar una actualización de estado como no urgente, de modo que React pueda mantener la interfaz receptiva mientras esa actualización se procesa en segundo plano.
function ProductSearch() {
const [query, setQuery] = useState("");
const [results, setResults] = useState([]);
const [isPending, startTransition] = useTransition();
function handleChange(e) {
const value = e.target.value;
setQuery(value); // urgent — keep input snappy
startTransition(() => {
// non-urgent — can be interrupted
setResults(filterProducts(value));
});
}
return (
<>
<input value={query} onChange={handleChange} />
{isPending && <span className="text-gray-400">Updating…</span>}
<ResultsList items={results} />
</>
);
}
Con este patrón, la escritura en un cuadro de búsqueda se mantiene fluida incluso mientras se filtran miles de elementos en segundo plano.
Suspense desempeña un papel similar de transmisión en tiempo real en el cliente, al igual que lo hace en PPR en el servidor: en lugar de bloquear toda la página mientras se cargan los datos, permite que las partes de la interfaz se resuelvan de forma independiente. Junto con el Next.js App Router, esto también permite que los componentes del servidor se transmitan progresivamente en la página en lugar de retrasar toda la carga.
useDeferredValue aborda un caso relacionado pero distinto: actualizaciones costosas provocadas por valores provenientes de props o contexto, en lugar de del estado local del componente. Permite a React retrasar el cálculo de esas partes costosas hasta que tenga tiempo disponible.
Para los equipos que trabajan con React, Next.js, TypeScript, Redux y Tailwind CSS, este modelo de programación es importante más allá de los hooks individuales: los patrones asíncronos más recientes en Redux Toolkit y la forma en que funcionan las Server Actions de Next.js en el fondo dependen ambos del mismo mecanismo de programación concurrente que ahora ofrece React. La concurrencia no es algo que se active directamente; es una capacidad que React aplica automáticamente una vez que sus componentes están estructurados de manera que permita interrumpir y reanudar su renderizado.
Qué recordar
En ambas técnicas, la lección fundamental es la misma: tratar toda una página o toda una renderización como una unidad indivisible es lo que causa lentitud, no necesariamente un código ineficiente. La renderización concurrente no se trata de escribir código más rápido, sino de programar de manera más inteligente el código que ya se tiene. En la práctica, eso significa posponer las actualizaciones de estado no urgentes con useTransition, transmitir datos en streaming con Suspense y probar en dispositivos de menor rendimiento, ya que allí son más visibles los beneficios de la concurrencia. Combinada con el pre-renderizado parcial en el lado del servidor, estas herramientas permiten que una única ruta o un único árbol de componentes entregue contenido estático al instante, mientras que el contenido dinámico se transmite en streaming solo cuando está listo: lo mejor de ambos mundos de la renderización, sin necesidad de reconstruir toda la arquitectura alrededor de uno u otro extremo.
Lecturas relacionadas
- Dentro de la reescritura en Go de TypeScript 7: Mejoras de velocidad sin cambios en el código — Aprenda cómo el compilador basado en Go de TypeScript 7 permite generaciones 8-12 veces más rápidas, por qué funciona este cambio de arquitectura y cómo actualizar de forma segura proyectos existentes.
- Primitivas SSR de React 19.2: Activity, cacheSignal y PPR explicados — Aprenda cómo el nuevo componente Activity, cacheSignal y el Pre-rendering parcial de React 19.2 brindan a los desarrolladores un control directo sobre el rendimiento del renderizado en servidor.