โ‡  chan.dev / posts

React 19: The Big Picture

๐ŸŒฑ This post is in the growth phase. It may still be useful as it grows up.

An App Dev's Guide to React 19:
What You Need to Know.
And Everything You Can Ignore.

chan.dev/react19

I'm @chantastic.

  • I used to host React Podcast
  • I work at WorkOS, where we build the best login box on the planet.
  1. Encourages TypeScript ๐Ÿง™
  2. Endorses Testing-Library ๐Ÿ™
  3. Embraces compilers ๐Ÿค–
  4. Engages the platform ๐ŸŒ

React 19 feature quadrants

quadrantChart x-axis Internal --> External y-axis Removed APIs --> New APIs quadrant-1 Depends quadrant-2 At release quadrant-3 Today quadrant-4 Tomorrow React Compiler: [0.5, 0.9] RSC and Server Actions: [0.75, 0.75] Actions: [0.25, 0.8] "Metadata, scripts, and stylesheets": [0.25, 0.7] PropTypes and defaultProps: [0.5, 0.35] PropTypes and defaultProps: [0.5, 0.35] Legacy Render: [0.5, 0.25] Legacy Context: [0.25, 0.3] Testing Utilities: [0.25, 0.2] SECRET_INTERNALS: [0.75, 0.2]

API Removals

React 18.3 warns for all removed APIs.
react-codemod is available for project-wide migrations.

You canโ€™t get fired with React 19

โŒ SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
โœ… _DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE




You own what you (npm) install
โ€” 12k files with SECRET_INTERNALS references in GitHub

Type Safety and React 19

Runtime prop-checking removed

import PropTypes from 'prop-types';
Heading.propTypes = {
text: PropTypes.string,
};
Heading.defaultProps = {
text: 'Hello, world!',
};
interface Props {
text?: string;
}
export function Heading({ text = 'Hello, world!' }: Props) {
return <h1>{text}</h1>;
}

Better useReducer typings

useReducer<React.Reducer<State, Action>>((state, action) => state)
useReducer((state: State, action: Action) => state)

useRef requires an argument

useRef();
useRef(undefined);
// consiquently, MutableRef is now deprecated

ref cleanup required

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

ReactElement changed from any to unknown

type Example = ReactElement["props"];
// ^? Now 'unknown' (not 'any')
// (Has no effect where type arguments are passed)

The JSX namespace in TypeScript

global.d.ts
declare module "react" {
namespace JSX {
interface IntrinsicElements {
"my-element": {
myElementProps: string;
};
}
}
}

See the React 19 RC Upgrade Guide for details and codemods.

Testing and React 19

Hey, just use Testing-Library, already.
Oh. And act is in react now.


chan.dev/react19-migrations