Skip to content
Nicolas Chiong· 4 min read

A field guide to React 19.2: six features worth your time

A practical reference to the parts of React 19.2 I actually reach for, with code for the Activity component, useEffectEvent, partial pre-rendering, and the new DevTools tracks.

A field guide to React 19.2: six features worth your time cover

React 19.2 shipped on October 1, 2025, the third release in under a year after 19.0 in December and 19.1 in June. I upgraded a side project the same week and kept notes on what was useful versus what was noise. This is that field guide: the features I now reach for, with the smallest snippet that makes each one click.

1. <Activity> for state you do not want to throw away

The pattern most of us still ship is {isVisible && <Page />}. It works, but the moment a tab goes away, its state, scroll position, and in-flight requests die with it. <Activity> keeps the subtree alive while hiding it.

// Before: state is destroyed when the tab hides
{tab === 'profile' && <ProfilePanel />}

// After: state survives, effects unmount, updates defer
<Activity mode={tab === 'profile' ? 'visible' : 'hidden'}>
  <ProfilePanel />
</Activity>

There are two modes in 19.2. hidden unmounts effects and defers updates until React has nothing else to do, so a hidden subtree never steals time from what is on screen. visible mounts effects and renders normally. The payoff: back navigation keeps form inputs, and you can pre-render the screen a user is likely to hit next while the current one stays smooth. Mux wrote up using it to keep video players warm across navigation, which is the kind of thing that used to need a custom keep-alive hack.

2. useEffectEvent to stop lying to the dependency array

This is the one I was waiting for. The old problem: you read a value inside an effect that is not really part of the effect's reactive logic, and now changing that value re-runs the whole thing.

function ChatRoom({ roomId, theme }) {
  const onConnected = useEffectEvent(() => {
    showNotification('Connected!', theme); // always the latest theme
  });

  useEffect(() => {
    const conn = createConnection(serverUrl, roomId);
    conn.on('connected', () => onConnected());
    conn.connect();
    return () => conn.disconnect();
  }, [roomId]); // theme is NOT a dependency, and that is correct now
}

Before this, changing theme reconnected the chat room, which is absurd. The usual fix was to disable the lint rule and drop the dependency, which quietly breaks the linter's ability to catch real mistakes later. useEffectEvent splits the "event" part out so it always sees fresh props and state without being a dependency. Two rules to remember: do not put the effect event in the dependency array, and declare it in the same component or hook as its effect. The linter enforces both once you move to eslint-plugin-react-hooks v6.

The mental model: if a function is conceptually an event that happens to fire from inside an effect, it is an effect event. Do not wrap everything in it just to silence a warning.

Here is a short, honest take on whether it earns its keep:

3. Partial pre-rendering for the static-shell, dynamic-fill split

React 19.2 lets you pre-render the static parts of an app, serve that shell from a CDN, and resume rendering later to fill in the dynamic bits.

// Build time: render what is static, save the rest
const { prelude, postponed } = await prerender(<App />, {
  signal: controller.signal,
});
await savePostponedState(postponed);

// Request time: resume into an SSR stream
const postponed = await getPostponedState(request);
const stream = await resume(<App />, postponed);

There is also resumeAndPrerender if you want static HTML for SSG instead of a live stream. This is plumbing most people will get through a framework rather than call by hand, but knowing the shape helps when you are debugging why a route hydrates the way it does.

4. Performance Tracks in Chrome DevTools

19.2 adds custom React tracks to Chrome performance profiles. The Scheduler track shows what React is working on by priority, so blocking work from a click is visually separated from transition work inside startTransition. The Components track shows the tree React is rendering or running effects on, with labels like "Mount" and "Blocked." I used it to find a transition that was being starved by a high-priority render, which would have been guesswork before.

5. Batched Suspense reveals during SSR

A quieter fix that changes how pages feel. Previously, server-streamed Suspense boundaries popped in one by one as each resolved. Now React batches reveals for a short window so more content appears together, matching client behavior and setting up cleaner View Transitions. The safeguard worth knowing: if total load time approaches the 2.5s LCP threshold, React stops batching and reveals immediately rather than hurt your Core Web Vitals.

6. Smaller changes that bite if you ignore them

A few notable items from the changelog:

ChangeWhy you care
Default useId prefix is now _r_Old :r: and «r» were invalid for view-transition-name; update any hardcoded ID assertions in tests
eslint-plugin-react-hooks v6Flat config by default, opt-in React Compiler rules; needed for useEffectEvent linting
Web Streams SSR for NodeAvailable now, but Node Streams are still faster and support compression, so prefer them

That last row is a trap. Web Streams in Node sound modern, but the React team explicitly recommends renderToPipeableStream because Web Streams skip compression by default and you can silently lose the benefit of streaming.

What I would actually adopt first

If you upgrade today, useEffectEvent is the change that pays off immediately and lets you delete a pile of lint-rule suppressions. <Activity> is the one to design around next, because it quietly removes a whole category of "save the state before this unmounts" code. The rest is worth reading once so you recognize it when your framework starts leaning on it. My bet for the next year: Activity plus View Transitions becomes the default way we build navigation, and the hand-rolled keep-alive component finally goes extinct.

techreactjavascriptfrontendweb-dev

References

  1. react.devReact Team (react.dev)
  2. blog.logrocket.comLogRocket Blog
  3. mux.comMux Blog
  4. dev.toThis Week In React #252 (Sebastien Lorber)
  5. react.devReact useEffectEvent docs

Related writing

← PreviousA field guide to the Steam Summer Sale 2026

Let's make something useful.

Start a conversation