React 19.2: Activity Component y Partial Pre-rendering Cambian Todo
Hola HaWkers, React 19.2 fue lanzado en octubre de 2025 y trajo features que cambian fundamentalmente cómo construimos aplicaciones React. El Activity component y Partial Pre-rendering son game-changers.
Vamos a analizar cada novedad y cómo aplicar en tu próximo proyecto.
La Evolución de React 19
Desde diciembre de 2024, React 19 ha evolucionado rápidamente. Ve el timeline:
Timeline de Lanzamientos
Versiones de React 19:
| Versión | Fecha | Destacados |
|---|---|---|
| v19.0.0 | Diciembre 2024 | Server Components, Actions |
| v19.1.0 | Marzo 2025 | Mejoras de performance |
| v19.2.0 | Octubre 2025 | Activity, PPR, useEffectEvent |
React 19 completa la transición de React para una arquitectura async-first, el mayor cambio desde React Hooks.
Activity Component: Pre-renderización Inteligente
Qué Es el Activity
El componente Activity permite pre-renderizar y mantener partes ocultas de la aplicación renderizadas sin impactar la performance de lo que está visible.
Casos de uso:
- Pre-renderizar rutas: Páginas que el usuario probablemente va a acceder
- Preservar estado: Mantener estado de partes navegadas
- Transiciones suaves: Navegar sin loading
- Optimización de UX: Experiencia instantánea
Cómo Funciona
import { Activity } from 'react';
function App() {
const [currentTab, setCurrentTab] = useState('home');
return (
<div>
<TabBar current={currentTab} onChange={setCurrentTab} />
{/* Tab activa - renderiza normalmente */}
<Activity mode={currentTab === 'home' ? 'visible' : 'hidden'}>
<HomeTab />
</Activity>
{/* Tab oculta - pre-renderizada pero no impacta performance */}
<Activity mode={currentTab === 'profile' ? 'visible' : 'hidden'}>
<ProfileTab />
</Activity>
{/* Tab oculta - estado preservado aunque no visible */}
<Activity mode={currentTab === 'settings' ? 'visible' : 'hidden'}>
<SettingsTab />
</Activity>
</div>
);
}Modos del Activity
Opciones disponibles:
| Modo | Comportamiento |
|---|---|
visible |
Renderiza normalmente, visible al usuario |
hidden |
Pre-renderizado pero oculto, estado preservado |
Beneficios de Performance
Comparación de navegación:
// ANTES: Sin Activity - re-render a cada navegación
function OldApp() {
const [tab, setTab] = useState('home');
// Cada cambio de tab destruye y recrea el componente
return (
<div>
{tab === 'home' && <HomeTab />}
{tab === 'profile' && <ProfileTab />}
</div>
);
}
// DESPUÉS: Con Activity - estado preservado
function NewApp() {
const [tab, setTab] = useState('home');
// Componentes pre-renderizados, navegación instantánea
return (
<div>
<Activity mode={tab === 'home' ? 'visible' : 'hidden'}>
<HomeTab />
</Activity>
<Activity mode={tab === 'profile' ? 'visible' : 'hidden'}>
<ProfileTab />
</Activity>
</div>
);
}
Partial Pre-rendering (PPR)
Qué Es PPR
Partial Pre-rendering permite pre-renderizar partes estáticas de la aplicación y servirlas de un CDN, llenando con contenido dinámico después.
El flujo:
- Build time: Partes estáticas pre-renderizadas
- CDN: Shell servido instantáneamente
- Runtime: Contenido dinámico llena el shell
- Resultado: Time-to-first-byte mínimo
Implementación Práctica
// page.jsx - Partial Pre-rendering
import { Suspense } from 'react';
// Esta parte es pre-renderizada en el build
export default function ProductPage({ productId }) {
return (
<div>
{/* Header estático - pre-renderizado */}
<Header />
<Navigation />
{/* Contenido dinámico - carga después */}
<Suspense fallback={<ProductSkeleton />}>
<ProductDetails productId={productId} />
</Suspense>
{/* Reviews dinámicos */}
<Suspense fallback={<ReviewsSkeleton />}>
<ProductReviews productId={productId} />
</Suspense>
{/* Footer estático - pre-renderizado */}
<Footer />
</div>
);
}Ganancias de Performance
Métricas observadas:
| Métrica | Sin PPR | Con PPR | Mejora |
|---|---|---|---|
| TTFB | 800ms | 50ms | 94% |
| LCP | 2.5s | 1.2s | 52% |
| FCP | 1.8s | 0.3s | 83% |
Partial Pre-rendering combina lo mejor de SSG y SSR: velocidad de estático con dinamismo de servidor.
useEffectEvent Hook
El Problema Que Resuelve
Antes de useEffectEvent, lidiar con callbacks en effects era problemático:
// ANTES: Problema con dependencias
function ChatRoom({ roomId, onMessage }) {
useEffect(() => {
const connection = createConnection(roomId);
connection.on('message', (msg) => {
// onMessage cambia a cada render, causando reconexión
onMessage(msg);
});
return () => connection.close();
}, [roomId, onMessage]); // onMessage como dependencia = problema
}La Solución Con useEffectEvent
// DESPUÉS: useEffectEvent resuelve
import { useEffectEvent } from 'react';
function ChatRoom({ roomId, onMessage }) {
// Crea un event handler estable
const handleMessage = useEffectEvent((msg) => {
onMessage(msg);
});
useEffect(() => {
const connection = createConnection(roomId);
connection.on('message', handleMessage);
return () => connection.close();
}, [roomId]); // onMessage no necesita ser dependencia!
}Cuándo Usar
Casos de uso ideales:
- Event handlers en effects: Callbacks que no deben re-trigger el effect
- Analytics: Tracking que necesita valores actuales
- Notificaciones: Handlers que cambian pero no deben reconectar
- WebSockets: Callbacks de mensaje estables
// Ejemplo: Analytics sin re-trigger
function ProductPage({ product, analytics }) {
const trackView = useEffectEvent(() => {
// Siempre usa el analytics más reciente
analytics.track('product_view', { id: product.id });
});
useEffect(() => {
trackView();
}, [product.id]); // analytics no es dependencia
}
cacheSignal API
Qué Es cacheSignal
La API cacheSignal permite crear señales de cache para invalidar datos de forma reactiva.
import { cacheSignal, use } from 'react';
// Crea un signal de cache para productos
const productCache = cacheSignal();
async function fetchProduct(id) {
const response = await fetch(`/api/products/${id}`);
return response.json();
}
function ProductDetails({ productId }) {
// use() con cache signal
const product = use(fetchProduct(productId), {
signal: productCache
});
return (
<div>
<h1>{product.name}</h1>
<p>{product.description}</p>
<button onClick={() => productCache.invalidate()}>
Recargar
</button>
</div>
);
}Invalidación Granular
// Invalidar cache específico
productCache.invalidate(); // Invalida todos los productos
// Invalidar por clave
productCache.invalidate(productId); // Invalida producto específico
// Invalidar con condición
productCache.invalidateIf((key) => key.startsWith('featured-'));
Performance Tracks
Debugging de Performance
React 19.2 introdujo Performance Tracks para debugging avanzado de performance.
Lo que muestra:
- Render timing: Cuánto tiempo cada componente lleva
- Suspense boundaries: Cuándo y por qué suspenden
- Transitions: Duración y estados
- Effects: Timing de effects y cleanup
Cómo Usar
// Activar Performance Tracks en dev
import { enableProfiler } from 'react-devtools';
enableProfiler({
tracks: true,
showSuspenseFallbacks: true,
highlightUpdates: true
});Integración Con DevTools
React DevTools 5.x:
- Visualización de tracks en Profiler
- Timeline de Suspense
- Flamegraph mejorado
- Métricas de re-render
Migrando Para React 19.2
Paso a Paso
1. Actualiza dependencias:
npm install react@19.2.0 react-dom@19.2.02. Verifica compatibilidad:
// React 19.2 requiere:
// - Node.js 18+
// - Bundler moderno (Vite, webpack 5+)
// - TypeScript 5.0+ (si usa TS)3. Adopta features gradualmente:
// Comienza con Activity en áreas de navegación
<Activity mode={isActive ? 'visible' : 'hidden'}>
<ExpensiveComponent />
</Activity>
// Después agrega PPR en páginas estáticas
// Por último, migra effects para useEffectEventProblemas Comunes
Errores frecuentes:
| Error | Causa | Solución |
|---|---|---|
| Activity not defined | Import faltando | import { Activity } from 'react' |
| Hydration mismatch | Server/Client diff | Verificar logs de diff |
| useEffectEvent in non-effect | Uso incorrecto | Usar apenas para effects |
React 19 vs Alternativas
Comparación Con Frameworks
React 19.2 vs otros:
| Feature | React 19.2 | Svelte 5 | Vue 3.5 | Solid 2 |
|---|---|---|---|---|
| Server Components | Sí | Parcial | Nuxt | No |
| PPR | Sí | No | No | No |
| Activity-like | Sí | No | KeepAlive | No |
| Signals | Via hooks | Nativo | Nativo | Nativo |
Cuándo Elegir React 19
React 19.2 es ideal para:
- Aplicaciones enterprise con SSR
- Dashboards complejos con muchas tabs
- E-commerce con PPR
- Apps que necesitan estado preservado
El Futuro de React
Roadmap 2026
Lo que esperar:
- React Compiler GA: Optimización automática de memoization
- Más APIs de cache: Invalidación aún más granular
- Activity mejorado: Más modos y opciones
- DevTools AI: Sugerencias de optimización
Impacto en el Mercado
Tendencias:
- React mantiene posición de líder
- Next.js como principal framework
- Server Components como estándar
- Performance como diferencial
Conclusión
React 19.2 representa la madurez de la visión async-first de React. Activity component y Partial Pre-rendering resuelven problemas reales de UX que desarrolladores enfrentan hace años.
Si aún no migraste para React 19, ahora es el momento. Las features de performance y DX justifican el esfuerzo de actualización.
Para entender más sobre el ecosistema JavaScript en 2025, te recomiendo echar un vistazo al artículo sobre TypeScript Supera Python donde analizamos los lenguajes más usados.

