React 19 introduces Actions, a new compiler, and improved hooks for simpler data mutations. Combined with Laravel APIs, it creates powerful, intuitive applications. At ZIRA Software, React 19 reduced our form handling code by 50%.
React 19 Key Features
React 19 Highlights
├── Actions - Simplified async mutations
├── React Compiler - Automatic optimization
├── use() hook - Async data in render
├── useFormStatus - Form state management
├── useOptimistic - Optimistic UI updates
└── Document metadata - Native title/meta
Actions with Laravel
// Traditional approach (React 18)
function ContactForm() {
const [isPending, setIsPending] = useState(false);
const [error, setError] = useState(null);
async function handleSubmit(e) {
e.preventDefault();
setIsPending(true);
setError(null);
try {
const formData = new FormData(e.target);
await fetch('/api/contact', {
method: 'POST',
body: formData,
});
} catch (err) {
setError(err.message);
} finally {
setIsPending(false);
}
}
return <form onSubmit={handleSubmit}>...</form>;
}
// React 19 with Actions
function ContactForm() {
async function submitContact(formData: FormData) {
'use server';
const response = await fetch(`${process.env.LARAVEL_API}/contact`, {
method: 'POST',
body: JSON.stringify(Object.fromEntries(formData)),
headers: { 'Content-Type': 'application/json' },
});
if (!response.ok) throw new Error('Failed to submit');
return response.json();
}
return (
<form action={submitContact}>
<input name="name" required />
<input name="email" type="email" required />
<textarea name="message" required />
<SubmitButton />
</form>
);
}
function SubmitButton() {
const { pending } = useFormStatus();
return (
<button type="submit" disabled={pending}>
{pending ? 'Sending...' : 'Send Message'}
</button>
);
}
useActionState Hook
// React 19 - useActionState for form state
import { useActionState } from 'react';
async function createPost(prevState: any, formData: FormData) {
const response = await fetch(`${process.env.LARAVEL_API}/posts`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${getToken()}`,
},
body: JSON.stringify({
title: formData.get('title'),
content: formData.get('content'),
}),
});
if (!response.ok) {
const error = await response.json();
return { error: error.message };
}
return { success: true, post: await response.json() };
}
function CreatePostForm() {
const [state, formAction, isPending] = useActionState(createPost, null);
return (
<form action={formAction}>
<input name="title" placeholder="Title" required />
<textarea name="content" placeholder="Content" required />
{state?.error && <p className="error">{state.error}</p>}
{state?.success && <p className="success">Post created!</p>}
<button type="submit" disabled={isPending}>
{isPending ? 'Creating...' : 'Create Post'}
</button>
</form>
);
}
useOptimistic for Instant UI
import { useOptimistic, useTransition } from 'react';
function LikeButton({ post, initialLikes }: Props) {
const [optimisticLikes, addOptimisticLike] = useOptimistic(
initialLikes,
(currentLikes, _) => currentLikes + 1
);
const [isPending, startTransition] = useTransition();
async function handleLike() {
startTransition(async () => {
addOptimisticLike(1);
await fetch(`${process.env.LARAVEL_API}/posts/${post.id}/like`, {
method: 'POST',
headers: { 'Authorization': `Bearer ${getToken()}` },
});
});
}
return (
<button onClick={handleLike} disabled={isPending}>
❤️ {optimisticLikes}
</button>
);
}
use() Hook for Async Data
// React 19 - use() hook in render
import { use, Suspense } from 'react';
async function fetchUser(id: number) {
const response = await fetch(`${process.env.LARAVEL_API}/users/${id}`);
return response.json();
}
function UserProfile({ userId }: { userId: number }) {
// use() can read promises in render
const user = use(fetchUser(userId));
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
</div>
);
}
function App() {
return (
<Suspense fallback={<ProfileSkeleton />}>
<UserProfile userId={1} />
</Suspense>
);
}
React Compiler Benefits
// Before: Manual memoization required
const MemoizedComponent = memo(function ExpensiveList({ items }) {
const sortedItems = useMemo(() => {
return items.sort((a, b) => a.name.localeCompare(b.name));
}, [items]);
const handleClick = useCallback((id) => {
console.log('Clicked:', id);
}, []);
return sortedItems.map(item => (
<Item key={item.id} item={item} onClick={handleClick} />
));
});
// After: React 19 compiler handles automatically
function ExpensiveList({ items }) {
const sortedItems = items.sort((a, b) => a.name.localeCompare(b.name));
const handleClick = (id) => {
console.log('Clicked:', id);
};
return sortedItems.map(item => (
<Item key={item.id} item={item} onClick={handleClick} />
));
}
// Compiler automatically optimizes - no memo/useMemo/useCallback needed
Document Metadata
// React 19 - Native document metadata
function BlogPost({ post }) {
return (
<article>
<title>{post.title} | My Blog</title>
<meta name="description" content={post.excerpt} />
<link rel="canonical" href={`https://myblog.com/posts/${post.slug}`} />
<h1>{post.title}</h1>
<div>{post.content}</div>
</article>
);
}
Laravel API Integration
// app/Http/Controllers/Api/PostController.php
class PostController extends Controller
{
public function store(Request $request)
{
$validated = $request->validate([
'title' => 'required|string|max:200',
'content' => 'required|string',
]);
$post = $request->user()->posts()->create($validated);
return new PostResource($post);
}
public function like(Post $post)
{
$post->likes()->firstOrCreate([
'user_id' => auth()->id(),
]);
return response()->json([
'likes_count' => $post->likes()->count(),
]);
}
}
Conclusion
React 19 with Laravel creates intuitive, performant applications. Actions simplify mutations, the compiler optimizes automatically, and new hooks improve developer experience.
Building React 19 applications? Contact ZIRA Software for full-stack development.