React 19 introduces several groundbreaking features that fundamentally change how you write React applications.
1. use() hook — read resources in render:
The use() hook lets you read the value of a Promise or Context directly in the render function. It suspends the component while the Promise is pending.
1import { use, Suspense } from "react";23// Server Component or anywhere with a promise4async function fetchUser(id: string) {5 const res = await fetch(`/api/users/${id}`);6 return res.json();7}89function UserProfile({ userId }: { userId: string }) {10 const user = use(fetchUser(userId)); // suspends11 return <div>{user.name}</div>;12}1314function App() {15 return (16 <Suspense fallback={<p>Loading...</p>}>17 <UserProfile userId="123" />18 </Suspense>19 );20}
2. Actions — async transitions:
Actions simplify async state transitions. The form action prop now accepts async functions:
1import { useState, useTransition } from "react";23function UpdateName() {4 const [name, setName] = useState("");5 const [isPending, startTransition] = useTransition();6 const [error, setError] = useState("");78 const submitAction = async () => {9 startTransition(async () => {10 const result = await updateName(name);11 if (result.error) {12 setError(result.error);13 }14 });15 };1617 return (18 <form action={submitAction}>19 <input value={name} onChange={e => setName(e.target.value)} />20 <button disabled={isPending}>Update</button>21 {error && <p style={{ color: "red" }}>{error}</p>}22 </form>23 );24}
3. useFormStatus — pending state for forms:
Read the submission status of the parent <form> from any child component:
1import { useFormStatus } from "react-dom";23function SubmitButton() {4 const { pending } = useFormStatus();5 return (6 <button type="submit" disabled={pending}>7 {pending ? "Submitting..." : "Submit"}8 </button>9 );10}1112// Must be inside a <form>13function MyForm() {14 return (15 <form action={serverAction}>16 <input name="email" type="email" />17 <SubmitButton />18 </form>19 );20}
4. Server Components and Server Actions:
"use server") let you call server functions directly from forms and client components1"use server";23async function createPost(formData: FormData) {4 const title = formData.get("title") as string;5 await db.insert(posts).values({ title });6 revalidatePath("/posts");7}
5. Document metadata in components:
Add <title>, <meta>, and <link> tags directly in components — React hoists them to <head>:
1function BlogPost({ post }) {2 return (3 <article>4 <title>{post.title}</title>5 <meta name="description" content={post.summary} />6 <meta property="og:image" content={post.image} />7 <h1>{post.title}</h1>8 <p>{post.content}</p>9 </article>10 );11}
6. Stylesheets:
Support for <link rel="stylesheet"> and <style> tags with automatic deduplication and ordering:
1function App() {2 return (3 <html>4 <head>5 <link rel="stylesheet" href="/styles/reset.css" precedence="reset" />6 <link rel="stylesheet" href="/styles/theme.css" precedence="default" />7 </head>8 <body>{children}</body>9 </html>10 );11}
7. ref as prop (no more forwardRef):
Pass ref as a regular prop to function components:
1// Before React 192const Input = forwardRef((props, ref) => <input ref={ref} {...props} />);34// React 195function Input({ ref, ...props }) {6 return <input ref={ref} {...props} />;7}