React 19 Features
React 19 brings a wave of powerful features focused on bridging the gap between client and server, simplifying asynchronous operations, and drastically reducing boilerplate for common patterns like data fetching and form handling.
1. The use() Hook
The use() hook is a game-changer. It allows you to read the value of a Promise or Context directly during render. Unlike other hooks, use() can be called conditionally or inside loops!
import { use, Suspense } from 'react';
const fetchUser = fetch('https://api.example.com/user').then(res => res.json());
function UserProfile() {
// use() suspends the component until the promise resolves
const user = use(fetchUser);
return <div>Welcome, {user.name}</div>;
}
export default function App() {
return (
<Suspense fallback={<div>Loading user...</div>}>
<UserProfile />
</Suspense>
);
}
2. Server Actions
Server actions allow you to define asynchronous functions that execute securely on the server but can be called directly from client components. This eliminates the need for manual API endpoints for simple mutations.
// actions.js (Server file)
'use server';
export async function updateName(formData) {
const name = formData.get('name');
await db.updateUser({ name });
return { success: true };
}
3. Form Actions
React 19 integrates natively with HTML <form> elements. You can pass a function (including Server Actions) directly to the action attribute. React handles the preventDefault and submission lifecycle automatically.
import { updateName } from './actions';
export default function ProfileForm() {
return (
// The action automatically receives FormData
<form action={updateName}>
<input name="name" type="text" />
<button type="submit">Update</button>
</form>
);
}
4. useActionState (formerly useFormState)
To handle the state (pending, error, success data) of a form action, React provides useActionState.
import { useActionState } from 'react';
import { updateName } from './actions';
export default function ProfileForm() {
// null is the initial state
const [state, formAction, isPending] = useActionState(updateName, null);
return (
<form action={formAction}>
<input name="name" type="text" />
<button type="submit" disabled={isPending}>
{isPending ? 'Updating...' : 'Update'}
</button>
{state?.error && <p className="error">{state.error}</p>}
</form>
);
}
5. useFormStatus
useFormStatus allows a child component inside a <form> to know the pending status of the parent form without needing to pass props down.
import { useFormStatus } from 'react-dom';
function SubmitButton() {
const { pending } = useFormStatus();
return (
<button type="submit" disabled={pending}>
{pending ? 'Saving...' : 'Save'}
</button>
);
}
6. Optimistic Updates (useOptimistic)
useOptimistic lets you immediately update the UI with a presumed successful state while a mutation is running in the background. If the mutation fails, React automatically rolls back the UI.
import { useOptimistic, useRef } from 'react';
import { likePost } from './actions';
function LikeButton({ initialLikes }) {
const [optimisticLikes, addOptimisticLike] = useOptimistic(
initialLikes,
(state, amount) => state + amount
);
const action = async () => {
addOptimisticLike(1); // Update UI instantly
await likePost(); // Perform network request
};
return <form action={action}><button>Likes: {optimisticLikes}</button></form>;
}
7. Document Metadata & Asset Loading
React 19 natively supports rendering <title>, <meta>, and <link> tags anywhere in your component tree. React hoists them to the document <head> automatically.
Additionally, asset loading APIs like preload, preconnect, and prefetchDNS have been introduced to optimize performance gracefully.
import { preconnect } from 'react-dom';
function Analytics() {
preconnect('https://analytics.example.com');
return <script src="..." />;
}