React 19: Complete Guide to Production-Ready Features
Guvantic Engineering
Guvantic Technical Publication
Master React 19's production features: Server Components, Actions, use() hook, and performance optimizations. Build faster, SEO-friendly apps with better Core Web Vitals.
The Problem: Too Much JavaScript
Modern React apps ship too much JavaScript. Bundle sizes keep growing, Core Web Vitals suffer, and user experience degrades on mobile.
React 19 Solutions:
React Server Components (RSC)
Server Component Example (Next.js App Router)
// app/products/page.tsx (Server Component)
import { db } from "@/lib/db";
import { ProductCard } from "@/components/ProductCard"; // Client Component
export default async function ProductsPage() {
// This runs on the server only - database queries are safe!
const products = await db.product.findMany({
where: { inStock: true },
take: 20,
});
return (
<div className="products-grid">
{products.map((product) => (
<ProductCard key={product.id} product={product} />
))}
</div>
);
}
Client Component (Interactive)
// components/ProductCard.tsx (Client Component)
"use client";
import { useState } from "react";
import { addToCart } from "@/actions/cart";
interface ProductCardProps {
product: { id: string; name: string; price: number };
}
export function ProductCard({ product }: ProductCardProps) {
const [isAdding, setIsAdding] = useState(false);
const handleAddToCart = async () => {
setIsAdding(true);
try {
await addToCart(product.id);
} finally {
setIsAdding(false);
}
};
return (
<div className="product-card">
<h3>{product.name}</h3>
<p>${product.price}</p>
<button onClick={handleAddToCart} disabled={isAdding}>
{isAdding ? "Adding..." : "Add to Cart"}
</button>
</div>
);
}
When to use each:
React Actions and Form Handling
Basic Action Example
"use client";
import { useActionState } from "react";
// Server Action (defined in server component)
async function submitContactForm(formData: FormData) {
"use server";
const name = formData.get("name");
const email = formData.get("email");
const message = formData.get("message");
await db.contact.create({ data: { name, email, message } });
// Return result for the client
return { success: true, message: "Thanks for contacting us!" };
}
// Client Component with Action
export function ContactForm() {
const [state, formAction, isPending] = useActionState(
submitContactForm,
{ success: false, message: "" }
);
return (
<form action={formAction}>
<div>
<label htmlFor="name">Name</label>
<input type="text" id="name" name="name" required />
</div>
<div>
<label htmlFor="email">Email</label>
<input type="email" id="email" name="email" required />
</div>
<div>
<label htmlFor="message">Message</label>
<textarea id="message" name="message" required />
</div>
<button type="submit" disabled={isPending}>
{isPending ? "Sending..." : "Send"}
</button>
{state.message && <p>{state.message}</p>}
</form>
);
}
Optimistic Updates
"use client";
import { useOptimistic, useTransition } from "react";
interface Comment { id: string; text: string; author: string; }
export function Comments({ initialComments }: { initialComments: Comment[] }) {
const [comments, setComments] = useState(initialComments);
const [optimisticComments, addOptimisticComment] = useOptimistic(
comments,
(state, newComment: Comment) => [...state, newComment]
);
const [isPending, startTransition] = useTransition();
async function submitComment(formData: FormData) {
const text = formData.get("comment") as string;
// Optimistically add comment
const tempId = `temp-${Date.now()}`;
addOptimisticComment({
id: tempId,
text,
author: "Current User",
});
// Actually save to database
startTransition(async () => {
const newComment = await createComment(text);
setComments((prev) =>
prev.map((c) => c.id === tempId ? newComment : c)
);
});
}
return (
<div>
<form action={submitComment}>
<input type="text" name="comment" placeholder="Write a comment..." />
<button type="submit" disabled={isPending}>
{isPending ? "Submitting..." : "Comment"}
</button>
</form>
<div className="comments">
{optimisticComments.map((comment) => (
<div key={comment.id} className="comment">
<strong>{comment.author}</strong>
<p>{comment.text}</p>
</div>
))}
</div>
</div>
);
}
The use() Hook
Data Fetching with use()
import { use, Suspense } from "react";
// Create a promise fetcher
async function fetchUser(id: string) {
const response = await fetch(`/api/users/${id}`);
if (!response.ok) throw new Error("Failed to fetch user");
return response.json();
}
// Component that uses the promise
function UserProfile({ userIdPromise }: { userIdPromise: Promise<string> }) {
const userId = use(userIdPromise); // Unwraps the promise
const user = use(fetchUser(userId)); // Another promise
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
</div>
);
}
// Parent component with Suspense
export default function App() {
const userIdPromise = fetch("/api/current-user").then(r => r.json());
return (
<Suspense fallback={<div>Loading user...</div>}>
<UserProfile userIdPromise={userIdPromise} />
</Suspense>
);
}
Context with use()
import { createContext, useContext, use } from "react";
// Create a context
const ThemeContext = createContext<"light" | "dark">("light");
function ThemedButton() {
// use() can read context
const theme = use(ThemeContext);
return (
<button className={theme === "dark" ? "dark-button" : "light-button"}>
Click me
</button>
);
}
Performance Impact on Core Web Vitals
Performance Checklist:
Next.js Configuration for Performance:
// next.config.js
module.exports = {
experimental: {
optimizeCss: true,
},
images: {
formats: ["image/avif", "image/webp"],
},
compiler: {
removeConsole: process.env.NODE_ENV === "production",
},
};
Guvantic Engineering
Engineering & System Architecture Division
Engineering teams at Guvantic deliver mission-critical software, high-concurrency microservices, and international organic positioning strategies for fast-growing companies in USA, UK, and India.