React 19.2 (released October 1, 2025) introduces a wave of refinements designed to improve rendering, performance, and developer ergonomics. In this post, walk through the new <Activity /> component, the useEffectEvent hook, cacheSignal, and SSR/streaming enhancements, with clear code examples and upgrade tips.
1. <Activity /> Component
What It Is
The new <Activity /> component allows parts of your UI to remain mounted and preserve state while being hidden or deprioritized — instead of being unmounted completely.
Why It Matters
- Previously, hiding components via conditionals (like
isVisible && <Sidebar />) destroyed state and effects. - With
<Activity mode="hidden">, effects pause, updates defer, but state is preserved. - Enables smoother transitions and faster UI toggles.
Example
import React, { useState } from 'react';
import { Activity } from 'react';
function Dashboard() {
const [showSidebar, setShowSidebar] = useState(true);
return (
<>
<button onClick={() => setShowSidebar(!showSidebar)}>
Toggle Sidebar
</button>
<Activity mode={showSidebar ? 'visible' : 'hidden'}>
<Sidebar />
</Activity>
<MainContent />
</>
);
}
Here, when showSidebar is false, <Sidebar /> is hidden but its scroll/input state remains intact.
2. useEffectEvent Hook
What It Is
The useEffectEvent hook introduces a stable way to create event handlers that always see the latest props and state, without forcing effects to re-run.
Why It Matters
Before, event handlers in effects could capture stale closures — forcing developers to add extra dependencies or re-attach effects unnecessarily.
useEffectEvent simplifies that pattern.
Example
import React, { useState, useEffect } from 'react';
import { useEffectEvent } from 'react';
function Counter() {
const [count, setCount] = useState(0);
const handleClick = useEffectEvent(() => {
console.log('Current count is', count);
});
useEffect(() => {
window.addEventListener('click', handleClick);
return () => window.removeEventListener('click', handleClick);
}, []); // effect runs once
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(prev => prev + 1)}>Increment</button>
</div>
);
}
✅ The effect attaches once, but the handler always has access to the latest count.
3. cacheSignal & Resource Lifetime Management
What It Is
cacheSignal complements React’s cache() API by providing a signal that fires when a cached resource’s lifetime ends.
Useful for cleaning up background operations tied to cached data.
Why It Matters
In Suspense + server components apps, caching resources is essential — but cleanup can be tricky.
cacheSignal gives a built-in AbortSignal to track disposal.
Example
import { cache, cacheSignal } from 'react';
const fetchUser = cache(async (id) => {
const res = await fetch(`/api/users/${id}`);
if (!res.ok) throw new Error('Failed to fetch');
return res.json();
});
function UserProfile({ userId }) {
const user = fetchUser(userId);
const signal = cacheSignal();
useEffect(() => {
const abortHandler = () => {
console.log('Cache aborted for', userId);
};
signal.addEventListener('abort', abortHandler);
return () => signal.removeEventListener('abort', abortHandler);
}, [signal, userId]);
return <div>{user.name}</div>;
}
Here, React triggers the abort signal when the cache entry expires or is invalidated — allowing safe cleanup.
4. Server-Side Rendering & Streaming Upgrades
What’s New
React 19.2 improves SSR streaming, partial pre-rendering, and hydration consistency.
- Partial Pre-Rendering: pre-render sections of UI early, then “resume” dynamic parts later.
- Batched Suspense reveals: multiple Suspense boundaries now stream together for smoother UX.
-
Web Streams for Node: New APIs like
renderToReadableStream,resume, andprerender.
Example: Partial Pre-Rendering
import { prerender, resume } from 'react-dom/server';
async function handleRequest(req, res) {
const { prelude, postponed } = await prerender(<App />, { signal: req.signal });
res.write(prelude);
const resumeStream = await resume(<App />, postponed);
resumeStream.pipe(res);
}
This hybrid approach improves Time-to-First-Byte and interactive speed for large apps.
5. Other Enhancements
- Performance Tracks in Chrome DevTools show new React Scheduler and component tracks.
-
Updated
useIdprefix (_r_instead of:r:) improves compatibility with web standards. -
eslint-plugin-react-hooks@6now supportsuseEffectEventand other React 19.2 APIs. - Internal bug fixes and streamlining for consistency across browsers and SSR frameworks.
Upgrade Tips
- Install latest React
npm install react@19.2 react-dom@19.2
-
Adopt features incrementally — e.g., replace legacy event patterns with
useEffectEvent. - Profile before/after using Chrome DevTools’ React Performance tracks.
- Update ESLint to v6 for hook rule support.
- Test SSR boundaries (especially if you use Next.js or Remix) for smooth streaming hydration.
Conclusion
React 19.2 focuses on refining how components mount, update, and interact with asynchronous work — without adding friction.
From <Activity /> to useEffectEvent, from cacheSignal to streaming SSR improvements, this release makes React apps smoother, more predictable, and easier to maintain.
Upgrade, explore, and profile your app — you’ll likely find subtle but impactful performance wins.
Top comments (0)