
React 19, released late 2024 and widely adopted through 2025-2026, brings the most significant changes since hooks. The new compiler, Server Components, Actions, and simplified Context are reshaping how React apps are built.
📋 Table of Contents
React Compiler — No More useMemo/useCallback
The React Compiler automatically memoizes components and values. Remove most useMemo, useCallback, and memo() calls.
// React 18: Manual memoization
const ExpensiveComponent = memo(({ data }) => {
const processed = useMemo(() => processData(data), [data]);
const handleClick = useCallback(() => onClick(data), [data, onClick]);
return <div onClick={handleClick}>{processed}</div>;
});
// React 19: Compiler handles it automatically
function ExpensiveComponent({ data }) {
const processed = processData(data);
return <div onClick={() => onClick(data)}>{processed}</div>;
}
Server Components
Server Components run on the server, access databases directly, and send zero JavaScript to the client. Default in Next.js 14+.
// app/users/page.tsx — runs on server, no JS sent to client
import { db } from '@/lib/db';
export default async function UsersPage() {
const users = await db.query('SELECT * FROM users LIMIT 10');
return (
<ul>
{users.map(u => <li key={u.id}>{u.name}</li>)}
</ul>
);
}
Actions — Server and Client
Actions replace the old event handler + fetch pattern. Handle pending states, errors, and optimistic updates automatically.
async function createUser(formData: FormData) {
'use server';
const name = formData.get('name') as string;
await db.insert('users', { name });
revalidatePath('/users');
}
export default function CreateUserForm() {
return (
<form action={createUser}>
<input name="name" placeholder="Name" />
<button type="submit">Create</button>
</form>
);
}
useActionState Hook
Tracks pending, error, and success state automatically. Replaces verbose useState + manual form handling.
import { useActionState } from 'react';
async function signUp(prevState, formData) {
const email = formData.get('email');
try {
await createAccount(email);
return { success: true };
} catch (e) {
return { error: e.message };
}
}
function SignUpForm() {
const [state, action, isPending] = useActionState(signUp, null);
return (
<form action={action}>
<input name="email" type="email" />
{state?.error && <p className="error">{state.error}</p>}
{state?.success && <p>Account created!</p>}
<button disabled={isPending}>
{isPending ? 'Creating...' : 'Sign Up'}
</button>
</form>
);
}
use() Hook — Async in Components
Read promises and context inline. No more useEffect for data fetching in client components.
import { use, Suspense } from 'react';
async function fetchUser(id) {
const res = await fetch(`/api/users/${id}`);
return res.json();
}
function UserCard({ userPromise }) {
const user = use(userPromise); // Suspense-aware
return <div>{user.name}</div>;
}
// In parent:
<Suspense fallback={<Skeleton />}>
<UserCard userPromise={fetchUser(userId)} />
</Suspense>
Simplified Context
Context providers now use <Context> directly — no more .Provider.
const ThemeContext = createContext('light');
// React 19: Direct
function App() {
return (
<ThemeContext value="dark">
<Page />
</ThemeContext>
);
}
// React 18: Required .Provider
function App() {
return (
<ThemeContext.Provider value="dark">
<Page />
</ThemeContext.Provider>
);
}
Conclusion
React 19 is the most developer-friendly version yet. The compiler eliminates performance boilerplate, Server Components reduce bundle size, and Actions simplify form handling. If you are still on React 17 or 18, upgrade now.
📚 You might also like
🔗 Share this article




✍️ Leave a Comment