DEV Community

Cover image for What’s New in React 19.2 – Activity API, useEffectEvent, cacheSignal & More
manikandan
manikandan

Posted on

What’s New in React 19.2 – Activity API, useEffectEvent, cacheSignal & More

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 />
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

✅ 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>;
}
Enter fullscreen mode Exit fullscreen mode

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, and prerender.

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);
}
Enter fullscreen mode Exit fullscreen mode

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 useId prefix (_r_ instead of :r:) improves compatibility with web standards.
  • eslint-plugin-react-hooks@6 now supports useEffectEvent and other React 19.2 APIs.
  • Internal bug fixes and streamlining for consistency across browsers and SSR frameworks.

Upgrade Tips

  1. Install latest React
   npm install react@19.2 react-dom@19.2
Enter fullscreen mode Exit fullscreen mode
  1. Adopt features incrementally — e.g., replace legacy event patterns with useEffectEvent.
  2. Profile before/after using Chrome DevTools’ React Performance tracks.
  3. Update ESLint to v6 for hook rule support.
  4. 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)