Back to blog

React 19.2: All New Features in the Third Major Release of 2025

Hello HaWkers, React 19.2 arrived in October 2025, marking the third significant release in the past year after React 19 in December 2024 and React 19.1 in June 2025.

Have you updated your projects yet? Let's explore the new features that promise to change how we build React applications.

React 19.2 Overview

React 19.2 continues the evolution of the async-first architecture introduced in React 19, bringing new primitives for rendering control and performance.

Main Additions

  • Activity component - New primitive for organizing parts of your app
  • useEffectEvent - Hook for events inside effects
  • cacheSignal - Cache control for Server Components
  • Performance Tracks - New profiling tool
  • Partial Pre-rendering - Partial pre-rendering of your application

Activity Component

Activity is a new primitive that lets you break your app into "activities" that can be controlled and prioritized.

Basic Concept

import { Activity } from 'react';

function App() {
  const [activeTab, setActiveTab] = useState('home');

  return (
    <div>
      <TabBar activeTab={activeTab} onChange={setActiveTab} />

      <Activity mode={activeTab === 'home' ? 'visible' : 'hidden'}>
        <HomePage />
      </Activity>

      <Activity mode={activeTab === 'profile' ? 'visible' : 'hidden'}>
        <ProfilePage />
      </Activity>

      <Activity mode={activeTab === 'settings' ? 'visible' : 'hidden'}>
        <SettingsPage />
      </Activity>
    </div>
  );
}

Activity Modes

// visible - Renders and shows normally
<Activity mode="visible">
  <Content />
</Activity>

// hidden - Maintains state but hides from DOM
<Activity mode="hidden">
  <Content />
</Activity>

// Smooth transitions between states
function TabContent({ isActive, children }) {
  return (
    <Activity mode={isActive ? 'visible' : 'hidden'}>
      {children}
    </Activity>
  );
}

Activity Benefits

1. State preservation:
Unlike conditional rendering, Activity preserves all component state when hidden.

// Problem: State lost when switching tabs
function OldApproach({ activeTab }) {
  return (
    <>
      {activeTab === 'form' && <FormWithState />} {/* State reset */}
    </>
  );
}

// Solution: Activity preserves state
function NewApproach({ activeTab }) {
  return (
    <Activity mode={activeTab === 'form' ? 'visible' : 'hidden'}>
      <FormWithState /> {/* State maintained */}
    </Activity>
  );
}

2. Rendering prioritization:
React can prioritize visible activities over hidden ones.

// Visible activities have priority
<Activity mode="visible" priority="high">
  <CriticalContent />
</Activity>

<Activity mode="hidden" priority="low">
  <PreloadedContent />
</Activity>

useEffectEvent

The new useEffectEvent hook solves a classic problem: using current values inside effects without causing re-execution.

The Problem

// Problem: Effect re-runs whenever onMessage changes
function Chat({ onMessage }) {
  useEffect(() => {
    const connection = connect();
    connection.on('message', (msg) => {
      onMessage(msg); // onMessage is new reference each render
    });
    return () => connection.disconnect();
  }, [onMessage]); // Reconnects every render!
}

The Solution

import { useEffectEvent } from 'react';

function Chat({ onMessage }) {
  // Creates stable reference to callback
  const onMessageEvent = useEffectEvent(onMessage);

  useEffect(() => {
    const connection = connect();
    connection.on('message', (msg) => {
      onMessageEvent(msg); // Always uses most recent version
    });
    return () => connection.disconnect();
  }, []); // No dependencies, doesn't reconnect!
}

Practical Use Cases

// Logging with current values
function ProductPage({ productId, analytics }) {
  const logVisit = useEffectEvent(() => {
    analytics.logVisit(productId); // Always uses current productId
  });

  useEffect(() => {
    logVisit();
  }, []);

  return <Product id={productId} />;
}

// Timer with updated callback
function Timer({ onTick }) {
  const handleTick = useEffectEvent(onTick);

  useEffect(() => {
    const id = setInterval(() => {
      handleTick();
    }, 1000);
    return () => clearInterval(id);
  }, []);
}

cacheSignal

cacheSignal offers fine-grained control over Server Components cache.

Basic Usage

import { cacheSignal } from 'react';

async function ProductList() {
  // Signal for cache invalidation
  const signal = cacheSignal();

  const products = await fetchProducts({ signal });

  return (
    <ul>
      {products.map(p => (
        <li key={p.id}>{p.name}</li>
      ))}
    </ul>
  );
}

Manual Invalidation

// Server Action to invalidate cache
'use server';

import { invalidateCache } from 'react';

export async function updateProduct(id, data) {
  await db.products.update(id, data);

  // Invalidates cache for components using this signal
  invalidateCache('products');
}

Partial Pre-rendering

The most impactful feature in React 19.2 is Partial Pre-rendering, which allows pre-rendering static parts of your application.

How It Works

// Static layout pre-rendered
function Layout({ children }) {
  return (
    <html>
      <head>
        <title>My App</title>
      </head>
      <body>
        <Header /> {/* Static - pre-rendered */}
        <Sidebar /> {/* Static - pre-rendered */}

        <Suspense fallback={<Loading />}>
          {children} {/* Dynamic - rendered after */}
        </Suspense>

        <Footer /> {/* Static - pre-rendered */}
      </body>
    </html>
  );
}

Performance Benefits

Traditional flow:

  1. Request arrives
  2. Server renders everything
  3. Sends complete HTML
  4. User sees content

With Partial Pre-rendering:

  1. Request arrives
  2. Server sends pre-rendered shell immediately
  3. User sees structure instantly
  4. Dynamic content loads progressively
// Defining static vs dynamic parts
export default function Page() {
  return (
    <>
      {/* These parts come from CDN instantly */}
      <Navigation />
      <Hero />

      {/* This part is rendered on demand */}
      <Suspense fallback={<ProductSkeleton />}>
        <ProductRecommendations />
      </Suspense>

      {/* Static again */}
      <Footer />
    </>
  );
}

Performance Tracks

New tool for detailed performance profiling.

DevTools Integration

import { startTrack, endTrack } from 'react';

function ExpensiveComponent() {
  startTrack('ExpensiveComponent:render');

  const result = expensiveCalculation();

  endTrack('ExpensiveComponent:render');

  return <div>{result}</div>;
}

Visualization in React DevTools

The Profiler now shows:

  • Render time per track
  • Dependency cascade
  • Server Components vs Client Components impact
  • Cache hit/miss metrics

React Compiler Improvements

The React Compiler introduced in React 19 received significant improvements.

Enhanced Automatic Memoization

// React Compiler now optimizes automatically
function ProductCard({ product, onAddToCart }) {
  // Before: Needed useMemo/useCallback
  // Now: Compiler optimizes automatically

  const formattedPrice = formatCurrency(product.price);
  const handleClick = () => onAddToCart(product.id);

  return (
    <div onClick={handleClick}>
      <h3>{product.name}</h3>
      <p>{formattedPrice}</p>
    </div>
  );
}

Migrating to React 19.2

Updating Dependencies

npm install react@19.2.0 react-dom@19.2.0

Checking Compatibility

// Check version
import { version } from 'react';
console.log(version); // "19.2.0"

// Check if Activity is available
const hasActivity = typeof Activity !== 'undefined';

Enabling New Features

// next.config.js (for Next.js)
module.exports = {
  experimental: {
    ppr: true, // Partial Pre-rendering
    reactCompiler: true,
  },
};

Version Comparison

Feature React 19 React 19.1 React 19.2
Server Components Stable Stable Stable
Actions API New Improved Improved
use() API New Stable Stable
Compiler Beta Stable Improved
Activity - - New
useEffectEvent - - New
Partial Pre-rendering - Experimental Stable

Best Practices

When to Use Activity

// GOOD: Tabs with complex state
<Activity mode={activeTab === 'editor' ? 'visible' : 'hidden'}>
  <CodeEditor />
</Activity>

// GOOD: Modals that preserve state
<Activity mode={isModalOpen ? 'visible' : 'hidden'}>
  <Modal>
    <ComplexForm />
  </Modal>
</Activity>

// AVOID: Simple stateless content
// Use normal conditional rendering
{showContent && <SimpleContent />}

When to Use useEffectEvent

// GOOD: Callbacks in long-running effects
const handleMessage = useEffectEvent(onMessage);

// GOOD: Analytics and logging
const logEvent = useEffectEvent((event) => analytics.log(event));

// AVOID: Replacing useCallback for normal event handlers
// useCallback is still appropriate for component props

Conclusion

React 19.2 continues React's evolution towards a more efficient and flexible architecture. Activity and useEffectEvent solve real development problems, while Partial Pre-rendering offers significant performance gains.

The recommendation is to start experimenting with these features in new projects or isolated parts of existing projects before a complete migration.

If you want to deepen your knowledge in React and modern JavaScript, I recommend checking out another article: ECMAScript 2025: All New Features where you'll discover JavaScript features that complement React 19.2.

Let's go! 🦅

🎯 Join Developers Who Are Evolving

Thousands of developers already use our material to accelerate their studies and achieve better positions in the market.

Why invest in structured knowledge?

Learning in an organized way with practical examples makes all the difference in your journey as a developer.

Start now:

  • 1x of $4.90 on card
  • or $4.90 at sight

🚀 Access Complete Guide

"Excellent material for those who want to go deeper!" - John, Developer

Comments (0)

This article has no comments yet 😢. Be the first! 🚀🦅

Add comments