Handling forms in React previously required extensive boilerplate: declaring isLoading, errorMessage, and data with useState, preventing default behavior on submit, and managing async try/catch blocks. React 19 Actions streamline form mutations into simple, native functions.
Figure 15: Optimistic UI Flow: User Submits ➔ Instant UI Update ➔ Background Server Action ➔ Confirm or Rollback.
import React, { useActionState, useOptimistic } from 'react';
// Server Action function
async function updateLikeAction(previousCount, formData) {
// Simulate network delay to backend server
await new Promise(res => setTimeout(res, 1000));
return previousCount + 1;
}
export default function ArticleLikeWidget({ initialLikes }) {
// 1. useActionState manages confirmed count and pending status
const [likes, formAction, isPending] = useActionState(updateLikeAction, initialLikes);
// 2. useOptimistic updates UI immediately without waiting for server!
const [optimisticLikes, setOptimisticLikes] = useOptimistic(
likes,
(current, update) => current + update
);
const handleSubmit = async (formData) => {
// Instantly increment on screen!
setOptimisticLikes(1);
// Send request to server
await formAction(formData);
};
return (
<form action={handleSubmit}>
<button type="submit" disabled={isPending}>
♥ {optimisticLikes} {isPending ? '(Saving...)' : 'Likes'}
</button>
</form>
);
}
Now let us explore full-stack frameworks, SSR, and SSG in React SSR, SSG & Next.js.
Accelerate your React mastery by studying these tightly connected core tutorials:
Action props on HTML form elements.
Pending state transitions during async tasks.
Executing server mutations directly from client forms.