Back to articles
ReactReact 19

React 19 in Production: The Features I Actually Use

A year of React 19 on a real codebase — which of the headline features (Actions, use(), the compiler, Suspense upgrades) earned their place and which I still haven't touched.

Yash Thakur
4 min read
React 19 in Production: The Features I Actually Use

The short answer: After a year of React 19 in production, the feature I actually reach for daily is Actions (useActionState / useFormStatus), which quietly erased all my form-state boilerplate; the compiler and use() earned a place too, while several headline features still sit untouched in my codebase.

React 19 arrived with the usual mix of genuine upgrades and features that sound revolutionary in the keynote and then sit unused in your codebase for a year. Having now shipped it in production across a real app, here's my honest sort of what mattered — and what didn't, yet.

Actions quietly fixed form state

The feature I reach for most isn't flashy: it's Actions, and the useActionState / useFormStatus pair. Every React app accumulates the same sad boilerplate around forms — a loading boolean, an error state, a try/catch, a manual reset. Actions fold all of that into the framework.

No useState for pending, no manual error plumbing. On a form-heavy app this deleted a surprising amount of code and a whole category of "I forgot to reset loading in the catch block" bugs.

The compiler is the one that changes how you write

The React Compiler is the real headline, and unusually for a hyped feature, it earns it — because it lets you stop doing something. The entire ritual of useMemo, useCallback, and React.memo existed to hand-hold React through re-renders. The compiler memoizes automatically at build time, so most of that hand-wringing goes away.

The adjustment is psychological more than technical: you have to trust it and resist the muscle memory of wrapping everything. I still profile hot paths, but I write far fewer memo hooks, and the code reads better for it. The caveat: it only pays off if your components already follow the rules of React (no mutation, no side effects in render), so it doubles as an incentive to clean those up.

use() is elegant, and I use it sparingly

The use() hook — unwrapping a promise or context conditionally — is genuinely elegant, especially with Suspense. But in practice my data fetching already lives in React Query or server components, so use() shows up less than I expected. It's the right tool for reading a promise passed down from a server component to a client one, and I keep it for exactly that.

What I still haven't touched

Not everything found a home. Some of the lower-level ref and metadata APIs solve problems I don't have on this codebase. That's fine — a framework release is a menu, not a checklist, and adopting a feature because it exists rather than because you have the problem it solves is how you end up with a codebase that's an average of every blog post.

The honest take

React 19's best features are the ones that let you delete code: Actions kill form boilerplate, the compiler kills manual memoization. The flashier primitives are real but niche. If you're upgrading, start with the compiler and Actions, measure, and leave the rest until a concrete problem asks for it. That order has served me better than trying to adopt the whole release at once.

Written by Yash Thakur

Senior React Developer · 8+ years building for the web

More articles

Keep reading