1. The React Compiler (React Forget)
Previously, React required developers to manually opt into memoization via useMemo and useCallback to avoid redundant child renders. The new **React Compiler** parses your code and automatically memoizes structures under the hood.
2. Stateful Actions and new Hooks
React 19 introduces **Actions** — a native pattern for handling async mutations. When you trigger an action, React handles loading states, error boundaries, and optimistic updates automatically.
// Handling forms with useActionState
import { useActionState } from 'react';
async function updateProfile(prevState, formData) {
try {
await apiCall(formData.get('username'));
return { success: true, error: null };
} catch (err) {
return { success: false, error: err.message };
}
}
function ProfileForm() {
const [state, formAction, isPending] = useActionState(updateProfile, { success: false, error: null });
return (
<form action={formAction}>
<input name="username" />
<button disabled={isPending}>Update</button>
{state.error && <span>{state.error}</span>}
</form>
);
}
Additionally, useFormStatus lets child components tap into parent submission states, making it incredibly simple to render dynamic loading spinners inside form inputs.
3. Simplified APIs (Refs and Context)
React 19 strips away deprecated structures. You can now pass ref directly as a normal component property, meaning forwardRef is officially deprecated. Furthermore, Context can be consumed using the direct tag instead of .Provider.
// 1. Context without .Provider
<Theme value="dark">
<App />
</Theme>
// 2. Direct Ref Passing
function CustomInput({ ref, label }) {
return (
<label>
{label}
<input ref={ref} />
</label>
);
}
Discussion