Build performant applications with React Server Components in Google Antigravity with proper client and server boundaries
# React Server Components Architecture for Google Antigravity
React Server Components represent a paradigm shift in how we build React applications, enabling server-side rendering with zero client JavaScript by default. This guide establishes patterns for leveraging RSC with Google Antigravity, enabling Gemini 3 to generate optimal component architectures.
## Component Boundary Patterns
Understand when to use server vs client components:
```typescript
// Server Component (default) - app/products/page.tsx
import { db } from "@/lib/db";
import { ProductCard } from "@/components/ProductCard";
import { ProductFilters } from "@/components/ProductFilters";
// This runs only on the server
export default async function ProductsPage({
searchParams,
}: {
searchParams: { category?: string; minPrice?: string };
}) {
// Direct database access - no API needed
const products = await db.product.findMany({
where: {
category: searchParams.category,
price: searchParams.minPrice
? { gte: parseFloat(searchParams.minPrice) }
: undefined,
},
include: { reviews: { select: { rating: true } } },
});
return (
<div className="container mx-auto py-8">
<h1 className="text-3xl font-bold mb-6">Products</h1>
{/* Client component for interactivity */}
<ProductFilters />
<div className="grid grid-cols-3 gap-6">
{products.map((product) => (
// Server component - renders HTML only
<ProductCard key={product.id} product={product} />
))}
</div>
</div>
);
}
// Server Component - components/ProductCard.tsx
import { formatPrice } from "@/lib/utils";
import { AddToCartButton } from "./AddToCartButton";
import type { Product } from "@/types";
interface ProductCardProps {
product: Product & { reviews: { rating: number }[] };
}
export function ProductCard({ product }: ProductCardProps) {
const avgRating =
product.reviews.reduce((sum, r) => sum + r.rating, 0) /
(product.reviews.length || 1);
return (
<div className="border rounded-lg p-4">
<img src={product.imageUrl} alt={product.name} className="w-full h-48 object-cover" />
<h3 className="font-semibold mt-2">{product.name}</h3>
<p className="text-gray-600">{formatPrice(product.price)}</p>
<div className="flex items-center mt-2">
<span>⭐ {avgRating.toFixed(1)}</span>
<span className="text-gray-400 ml-2">({product.reviews.length})</span>
</div>
{/* Client component for cart interaction */}
<AddToCartButton productId={product.id} />
</div>
);
}
```
## Client Components
Design minimal client components for interactivity:
```typescript
// Client Component - components/AddToCartButton.tsx
"use client";
import { useState, useTransition } from "react";
import { addToCart } from "@/app/actions/cart";
import { useToast } from "@/hooks/useToast";
interface AddToCartButtonProps {
productId: string;
}
export function AddToCartButton({ productId }: AddToCartButtonProps) {
const [isPending, startTransition] = useTransition();
const { toast } = useToast();
const handleClick = () => {
startTransition(async () => {
const result = await addToCart(productId);
if (result.success) {
toast({ title: "Added to cart!", variant: "success" });
} else {
toast({ title: result.error, variant: "error" });
}
});
};
return (
<button
onClick={handleClick}
disabled={isPending}
className="mt-4 w-full bg-blue-600 text-white py-2 rounded hover:bg-blue-700 disabled:opacity-50"
>
{isPending ? "Adding..." : "Add to Cart"}
</button>
);
}
// Client Component - components/ProductFilters.tsx
"use client";
import { useRouter, useSearchParams } from "next/navigation";
import { useCallback } from "react";
export function ProductFilters() {
const router = useRouter();
const searchParams = useSearchParams();
const updateFilter = useCallback(
(key: string, value: string) => {
const params = new URLSearchParams(searchParams.toString());
if (value) {
params.set(key, value);
} else {
params.delete(key);
}
router.push(`?${params.toString()}`);
},
[router, searchParams]
);
return (
<div className="flex gap-4 mb-6">
<select
value={searchParams.get("category") || ""}
onChange={(e) => updateFilter("category", e.target.value)}
className="border rounded px-3 py-2"
>
<option value="">All Categories</option>
<option value="electronics">Electronics</option>
<option value="clothing">Clothing</option>
</select>
<input
type="number"
placeholder="Min price"
value={searchParams.get("minPrice") || ""}
onChange={(e) => updateFilter("minPrice", e.target.value)}
className="border rounded px-3 py-2 w-32"
/>
</div>
);
}
```
## Data Fetching Patterns
Optimize data loading with streaming:
```typescript
// app/dashboard/page.tsx
import { Suspense } from "react";
import { RevenueChart } from "@/components/dashboard/RevenueChart";
import { RecentOrders } from "@/components/dashboard/RecentOrders";
import { StatsCards } from "@/components/dashboard/StatsCards";
import { Skeleton } from "@/components/ui/Skeleton";
export default function DashboardPage() {
return (
<div className="space-y-6">
<h1 className="text-2xl font-bold">Dashboard</h1>
<Suspense fallback={<Skeleton className="h-32" />}>
<StatsCards />
</Suspense>
<div className="grid grid-cols-2 gap-6">
<Suspense fallback={<Skeleton className="h-80" />}>
<RevenueChart />
</Suspense>
<Suspense fallback={<Skeleton className="h-80" />}>
<RecentOrders />
</Suspense>
</div>
</div>
);
}
```
## Best Practices
1. **Default to server**: Use server components unless interactivity needed
2. **Push client boundary down**: Keep client components as leaves
3. **Composition over props**: Pass server components as children
4. **Streaming with Suspense**: Show content progressively
5. **Colocate data fetching**: Fetch where data is usedThis React prompt is ideal for developers working on:
By using this prompt, you can save hours of manual coding and ensure best practices are followed from the start. It's particularly valuable for teams looking to maintain consistency across their react implementations.
Yes! All prompts on Antigravity AI Directory are free to use for both personal and commercial projects. No attribution required, though it's always appreciated.
This prompt works excellently with Claude, ChatGPT, Cursor, GitHub Copilot, and other modern AI coding assistants. For best results, use models with large context windows.
You can modify the prompt by adding specific requirements, constraints, or preferences. For React projects, consider mentioning your framework version, coding style, and any specific libraries you're using.