React 19 New Features: Everything You Need to Know
React 19 New Features: Everything You Need to Know
import { useActionState } from 'react';
function UpdateProfile() {
const [state, submitAction, isPending] = useActionState(
async (previousState, formData) => {
const name = formData.get('name');
const result = await updateUser(name);
if (result.error) return { error: result.error };
return { success: true };
},
null
);
return (
<form action={submitAction}>
<input name="name" />
<button disabled={isPending}>
{isPending ? 'Saving...' : 'Save'}
</button>
{state?.error && <p>{state.error}</p>}
</form>
);
}import { useOptimistic } from 'react';
function TodoList({ todos }) {
const [optimisticTodos, addOptimisticTodo] = useOptimistic(
todos,
(state, newTodo) => [...state, { ...newTodo, pending: true }]
);
async function addTodo(formData) {
const title = formData.get('title');
addOptimisticTodo({ title, id: Date.now() });
await saveTodo(title);
}
return (
<>
{optimisticTodos.map(todo => (
<li key={todo.id} style={{ opacity: todo.pending ? 0.5 : 1 }}>
{todo.title}
</li>
))}
<form action={addTodo}>
<input name="title" />
<button>Add</button>
</form>
</>
);
}import { use } from 'react';
function UserProfile({ userPromise }) {
const user = use(userPromise);
return <h1>{user.name}</h1>;
}
// Can also read context conditionally
function ThemeButton({ showTheme }) {
if (showTheme) {
const theme = use(ThemeContext);
return <button className={theme}>Click</button>;
}
return <button>Click</button>;
}function BlogPost({ post }) {
return (
<article>
<title>{post.title}</title>
<meta name="description" content={post.summary} />
<h1>{post.title}</h1>
<p>{post.content}</p>
</article>
);
}function CustomInput({ ref, ...props }) {
return <input ref={ref} {...props} />;
}
// Usage
<CustomInput ref={myRef} placeholder="Type here" />React 19 brings major improvements to the developer experience with new hooks, better server component support, and simplified patterns. Here is a comprehensive overview of the key features.
1. Actions and useActionState
Actions simplify form handling and async mutations. The new useActionState hook replaces the need for manual loading and error state management.
import { useActionState } from 'react';
function UpdateProfile() {
const [state, submitAction, isPending] = useActionState(
async (previousState, formData) => {
const name = formData.get('name');
const result = await updateUser(name);
if (result.error) return { error: result.error };
return { success: true };
},
null
);
return (
<form action={submitAction}>
<input name="name" />
<button disabled={isPending}>
{isPending ? 'Saving...' : 'Save'}
</button>
{state?.error && <p>{state.error}</p>}
</form>
);
}import { useOptimistic } from 'react';
function TodoList({ todos }) {
const [optimisticTodos, addOptimisticTodo] = useOptimistic(
todos,
(state, newTodo) => [...state, { ...newTodo, pending: true }]
);
async function addTodo(formData) {
const title = formData.get('title');
addOptimisticTodo({ title, id: Date.now() });
await saveTodo(title);
}
return (
<>
{optimisticTodos.map(todo => (
<li key={todo.id} style={{ opacity: todo.pending ? 0.5 : 1 }}>
{todo.title}
</li>
))}
<form action={addTodo}>
<input name="title" />
<button>Add</button>
</form>
</>
);
}import { use } from 'react';
function UserProfile({ userPromise }) {
const user = use(userPromise);
return <h1>{user.name}</h1>;
}
// Can also read context conditionally
function ThemeButton({ showTheme }) {
if (showTheme) {
const theme = use(ThemeContext);
return <button className={theme}>Click</button>;
}
return <button>Click</button>;
}function BlogPost({ post }) {
return (
<article>
<title>{post.title}</title>
<meta name="description" content={post.summary} />
<h1>{post.title}</h1>
<p>{post.content}</p>
</article>
);
}function CustomInput({ ref, ...props }) {
return <input ref={ref} {...props} />;
}
// Usage
<CustomInput ref={myRef} placeholder="Type here" />