Implement efficient data fetching with React Server Components and Suspense
# Data Fetching Patterns for Google Antigravity
Master modern data fetching patterns using React Server Components and Suspense with Google Antigravity IDE.
## Server Components Data Fetching
```typescript
// app/users/page.tsx
import { Suspense } from "react";
import { UserList, UserListSkeleton } from "./user-list";
import { getUsers } from "@/lib/api";
// This component runs on the server - no client-side JavaScript
export default async function UsersPage() {
// Direct database or API calls without useEffect
const users = await getUsers();
return (
<main>
<h1>Users</h1>
<Suspense fallback={<UserListSkeleton />}>
<UserList users={users} />
</Suspense>
</main>
);
}
// lib/api.ts
import { db } from "@/lib/db";
import { cache } from "react";
// Deduplicate requests within the same render
export const getUsers = cache(async () => {
const users = await db.query.users.findMany({
with: { profile: true },
orderBy: (users, { desc }) => [desc(users.createdAt)]
});
return users;
});
export const getUser = cache(async (id: string) => {
const user = await db.query.users.findFirst({
where: (users, { eq }) => eq(users.id, id),
with: { profile: true, posts: true }
});
return user;
});
```
## Parallel Data Fetching
```typescript
// app/dashboard/page.tsx
import { Suspense } from "react";
import { getUser, getStats, getNotifications, getRecentActivity } from "@/lib/api";
export default async function DashboardPage() {
// Fetch all data in parallel
const [user, stats, notifications, activity] = await Promise.all([
getUser(),
getStats(),
getNotifications(),
getRecentActivity()
]);
return (
<div className="dashboard">
<UserHeader user={user} />
<StatsGrid stats={stats} />
<NotificationList notifications={notifications} />
<ActivityFeed activity={activity} />
</div>
);
}
// Alternative: Streaming with multiple Suspense boundaries
export default function DashboardPageStreaming() {
return (
<div className="dashboard">
<Suspense fallback={<HeaderSkeleton />}>
<UserHeaderAsync />
</Suspense>
<div className="grid">
<Suspense fallback={<StatsSkeleton />}>
<StatsGridAsync />
</Suspense>
<Suspense fallback={<NotificationsSkeleton />}>
<NotificationListAsync />
</Suspense>
</div>
<Suspense fallback={<ActivitySkeleton />}>
<ActivityFeedAsync />
</Suspense>
</div>
);
}
// Each component fetches its own data
async function UserHeaderAsync() {
const user = await getUser();
return <UserHeader user={user} />;
}
async function StatsGridAsync() {
const stats = await getStats();
return <StatsGrid stats={stats} />;
}
```
## Server Actions for Mutations
```typescript
// app/actions/users.ts
"use server";
import { revalidatePath, revalidateTag } from "next/cache";
import { redirect } from "next/navigation";
import { z } from "zod";
import { db } from "@/lib/db";
const createUserSchema = z.object({
name: z.string().min(1),
email: z.string().email()
});
export async function createUser(formData: FormData) {
const rawData = Object.fromEntries(formData);
const validated = createUserSchema.safeParse(rawData);
if (!validated.success) {
return { error: validated.error.flatten().fieldErrors };
}
try {
const user = await db.insert(users).values(validated.data).returning();
revalidateTag("users");
revalidatePath("/users");
redirect(`/users/${user[0].id}`);
} catch (error) {
return { error: { server: ["Failed to create user"] } };
}
}
export async function deleteUser(id: string) {
await db.delete(users).where(eq(users.id, id));
revalidateTag("users");
revalidatePath("/users");
}
```
## Best Practices
1. **Use Server Components** for static and dynamic data
2. **Fetch in parallel** with Promise.all when possible
3. **Stream with Suspense** for better perceived performance
4. **Deduplicate requests** with React cache
5. **Use Server Actions** for mutations
6. **Implement optimistic updates** for better UX
7. **Cache appropriately** at multiple levels
Google Antigravity optimizes data fetching patterns and suggests caching strategies for your application.This data-fetching 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 data-fetching 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 data-fetching projects, consider mentioning your framework version, coding style, and any specific libraries you're using.