The Complete Developer Guide to React 19, Part 2: New Enhancements

Authors
Hristo Totov
Software Engineer
@
Callstack

Ref as a prop

React 19 makes using forwardRef obsolete by adding ref as a default prop for function components just like children. This change will definitely simplify the way ref is utilized, especially for new developers as the concept can be a bit too complex to comprehend if you are new to React.

function MyInput({placeholder, ref}) {
return <input placeholder={placeholder} ref={ref} />
}
//...
<MyInput ref={ref} />
view raw RefAsProp.jsx hosted with ❤ by GitHub

To further simplify the process, the React team will provide a codemon to update existing forwardRef usage in codebases and eventually forwardRef will be deprecated.

An important thing to note here is that passing ref as a prop would not work on class components as ref references the component instance.

That’s not the only change refs are getting, however. In React 19, returning a cleanup function from ref callbacks will be supported as well:

<input
ref={(ref) => {
// NEW: return a cleanup function to reset
// the ref when element is removed from DOM.
return () => {
// ref cleanup
};
}}
/>

When the component unmounts, React calls the cleanup function returned from the ref callback. Returning anything else from a ref callback will be rejected by TypeScript, so implicit returns will now have to be modified:

- <div ref={current => (instance = current)} />
+ <div ref={current => {instance = current}} />

Diffs for Hydration Errors

The way errors are reported in the console for hydration errors in react-dom is massively improved in React 19 as well. Logging multiple errors in DEV mode with almost no useful information at all has now been changed to logging a single, informative message with a diff of the mismatch which will help developers quickly spot and fix a bug.

This change will also improve the debugging for the server-side react functionality because on the server we don’t have the Dev Tools equivalent as we do on the client side with browsers and logging more useful information will be of assistance.

An example of before:

screenshot with error warnings in console before

And after:

screenshot with error warnings in console after

Improved error reporting

Currently, duplicate errors are logged for caught errors filling the console with unnecessary messages. In React 19, error reporting is improved to remove duplication and provide clearer insights into component failures. Instead of multiple messages for every caught error, there is now a single error message with all the useful information included.

Additionally, two new root options to complement onRecoverableError are added:

  1. onCaughtError: called when React catches an error in an Error Boundary.
  2. onUncaughtError: called when an error is thrown and not caught by an Error Boundary.

Before:

Error reporting - before

After:

Error reporting - after

Context as a provider

Context consuming is getting a bit simpler with React 19. Developers no longer need to use <Context.Provider> but instead they could directly use the <Context> itself as a provider.

const ThemeContext = createContext('');
function App({children}) {
return (
<ThemeContext value="dark"> // Previously ThemeContext.Provider
{children}
</ThemeContext>
)};

The react team will be publishing a codemon to convert existing providers in codebases and eventually <Context.Provider> will be deprecated.

useDefferedValue initial value

Similar to useState, useDefferedValue will now also have an initial value available:

function Search({deferredValue}) {
// On initial render the value is ''.
// Then a re-render is scheduled with the deferredValue.
const value = useDeferredValue(deferredValue, '');
return (
<Results query={value} />
);
}

When initialValue is provided, useDeferredValue returns it as the value for the initial render of the component, scheduling a re-render with the deferred value in the background.

An example of why this would be useful is if you want to show stale content while the fresh content is still loading:

export default function App() {
const [query, setQuery] = useState('');
const deferredQuery = useDeferredValue(query);
return (
<>
<label>
Search albums:
<input value={query} onChange={e => setQuery(e.target.value)} />
</label>
<Suspense fallback={<h2>Loading...</h2>}>
<SearchResults query={deferredQuery} />
</Suspense>
</>
);
}

The query will update immediately, so the input will display the new value. However, the deferredQuery will keep its previous value until the data has loaded, so SearchResults will show the stale results for a bit.

Read the other parts of the guide

That's it for this part of the guide. You can check the previous part where we discuss streamlined Async Handling. In the final installment, we explore the upgraded resource support in React 19:

Insights

Learn more about React

cover

Jun 24Article

Writing Custom Renderers for React

Learn how React renderers work, why RNTL needed a new test renderer, and what it takes to connect React Reconciler to a host environment.

cover

Dec 18Live Stream

Building iOS Live Activities With React: Inside Voltra

Learn how to build iOS Live Activities and Dynamic Island experiences using pure JSX, no Swift or native code required.

cover

Nov 27Podcast

From React Native Web to React Strict DOM

Nicolas Gallagher (Meta) explains how React Strict DOM evolved from React Native Web, providing a shared syntax that compiles to native or web with zero overhead.

cover

Nov 21Podcast

React Foundation: New Governance Model for React and React Native

Seth Webster, Executive Director of the React Foundation, details its new governance model, Meta's role, and how partners like Callstack and Microsoft will ensure stability and scale.

cover

Apr 9Podcast

Exploring TanStack Ecosystem: From React Query to TanStack Start

Tanner Linsley breaks down TanStack’s evolution-from React Query to Start, and why client-first React apps still matter in today’s full-stack landscape.

Event Cover

Feb 20Live Stream

Create React App is Out: Exploring Alternatives & Community Proposals

CRA is now deprecated, so we explore other options for starting web React projects, going through Vite, TanStack Router, Parcel, and Rsbuild to check the developer experience.

Event Cover

Feb 13Live Stream

State of React 2024 Breakdown

Let's take a deep dive into the long-awaited State of React survey from 2024; brace yourselves for a two-hour ride.

cover

Sep 9Article

The Complete Developer Guide to React 19, Part 3: Upgraded Support

Learn how React 19's new features enhance SEO, page performance, and custom elements support for better, faster web applications.

cover

Sep 2Article

The Complete Developer Guide to React 19, Part 1: Async Handling

Explore the key features of React 19 beta, focusing on new hooks that enhance async handling, state management, and form submissions.

cover

May 2Article

Understanding React Server Components

React Server Components (RSC) are still work in progress, but now it's the best time to explore these core concepts of future React. Find out why and how!

cover

Mar 19Tutorial

The Hard Way vs. The React Native AI SDK Way: Stop Writing Custom Modules for Every Model

Learn how React Native AI uses a unified provider model to switch between cloud and on-device LLMs without rewriting application logic, enabling reliable AI experiences online and offline.

cover

Mar 12Tutorial

Build Smarter Apps: Tool Calling & AI Orchestration Explained

Learn how on-device models in React Native can call tools, interact with external APIs, and return structured outputs you can use directly in application logic.

cover

Mar 5Tutorial

MLC LLM + React Native: On-Device AI Without the Pain

Learn how to run third-party on-device LLMs in React Native using MLC LLM. Choose your models, run them efficiently across platforms, and keep a unified JavaScript API with React Native AI.

cover

Feb 24Tutorial

Intelligent Fallbacks with Apple Intelligence in React Native

Learn how to use Apple’s built-in Foundation Models in React Native apps, reduce memory usage, and enable fast, fully on-device AI with React Native AI Apple.

cover

Feb 10Tutorial

What Is the React Native AI SDK? A Complete Intro & Quickstart

Learn why on-device AI matters for React Native apps, how local LLMs behave offline, and what problems React Native AI is designed to solve from day one.

cover

Jan 29Tutorial

Implementing an Android TurboModule with Kotlin

Learn how to implement a React Native TurboModule on Android, from the TypeScript spec and Codegen to the Kotlin implementation and package registration.

cover

Jan 19Tutorial

Working with Different Threads in Swift TurboModules

Learn how JavaScript, native module, background, and main threads interact in React Native TurboModules, and how to use GCD queues to run async work safely in Swift.

cover

Jan 9Tutorial

How to Add Type-Safe Constants to Swift TurboModules

Learn how to expose typed, immutable constants from a Swift TurboModule using Codegen, and get full end-to-end type safety between native and JavaScript.

cover

Dec 30Tutorial

Adding Event Emitters to Your TurboModule in Swift

Learn how to emit native events from a Swift TurboModule and subscribe to them in JavaScript, including proper memory management and Codegen integration.

cover

Dec 22Tutorial

Writing Your First TurboModule in Swift

Learn how to build a fully working TurboModule in Swift, integrate it with Codegen, and bridge it through Objective‑C inside an Expo app.