Master React Suspense streaming patterns for Google Antigravity IDE progressive loading
# React Suspense Streaming Patterns for Google Antigravity IDE
Build progressive loading experiences with React Suspense using Google Antigravity IDE. This guide covers streaming, parallel data fetching, and skeleton patterns.
## Parallel Data Fetching
```typescript
// src/app/dashboard/page.tsx
import { Suspense } from "react";
import { UserStats, RecentActivity, Notifications, QuickActions } from "./components";
async function getStats() {
const res = await fetch("/api/stats", { next: { revalidate: 60 } });
return res.json();
}
async function getActivity() {
const res = await fetch("/api/activity", { next: { revalidate: 30 } });
return res.json();
}
async function getNotifications() {
const res = await fetch("/api/notifications");
return res.json();
}
async function StatsSection() {
const stats = await getStats();
return <UserStats data={stats} />;
}
async function ActivitySection() {
const activity = await getActivity();
return <RecentActivity items={activity} />;
}
async function NotificationsSection() {
const notifications = await getNotifications();
return <Notifications items={notifications} />;
}
export default function DashboardPage() {
return (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<div className="lg:col-span-2">
<Suspense fallback={<StatsSkeleton />}>
<StatsSection />
</Suspense>
</div>
<div>
<Suspense fallback={<NotificationsSkeleton />}>
<NotificationsSection />
</Suspense>
</div>
<div className="lg:col-span-2">
<Suspense fallback={<ActivitySkeleton />}>
<ActivitySection />
</Suspense>
</div>
<div>
<QuickActions />
</div>
</div>
);
}
```
## Skeleton Components
```typescript
// src/components/skeletons.tsx
export function StatsSkeleton() {
return (
<div className="grid grid-cols-4 gap-4">
{[...Array(4)].map((_, i) => (
<div key={i} className="bg-gray-100 rounded-lg p-4 animate-pulse">
<div className="h-4 bg-gray-200 rounded w-1/2 mb-2" />
<div className="h-8 bg-gray-200 rounded w-3/4" />
</div>
))}
</div>
);
}
export function ActivitySkeleton() {
return (
<div className="space-y-3">
{[...Array(5)].map((_, i) => (
<div key={i} className="flex items-center gap-3 p-3 animate-pulse">
<div className="w-10 h-10 bg-gray-200 rounded-full" />
<div className="flex-1">
<div className="h-4 bg-gray-200 rounded w-3/4 mb-2" />
<div className="h-3 bg-gray-200 rounded w-1/2" />
</div>
</div>
))}
</div>
);
}
export function NotificationsSkeleton() {
return (
<div className="space-y-2">
{[...Array(3)].map((_, i) => (
<div key={i} className="p-3 bg-gray-100 rounded animate-pulse">
<div className="h-4 bg-gray-200 rounded w-full mb-2" />
<div className="h-3 bg-gray-200 rounded w-2/3" />
</div>
))}
</div>
);
}
```
## Nested Suspense
```typescript
// src/app/posts/[slug]/page.tsx
import { Suspense } from "react";
import { notFound } from "next/navigation";
async function getPost(slug: string) {
const res = await fetch("/api/posts/" + slug);
if (!res.ok) return null;
return res.json();
}
async function PostContent({ slug }: { slug: string }) {
const post = await getPost(slug);
if (!post) notFound();
return (
<article>
<h1 className="text-3xl font-bold mb-4">{post.title}</h1>
<div dangerouslySetInnerHTML={{ __html: post.content }} />
</article>
);
}
async function Comments({ postId }: { postId: string }) {
const res = await fetch("/api/posts/" + postId + "/comments");
const comments = await res.json();
return (
<section className="mt-8">
<h2 className="text-xl font-semibold mb-4">Comments ({comments.length})</h2>
{comments.map((comment: Comment) => (
<div key={comment.id} className="border-b py-4">
<p className="font-medium">{comment.author.name}</p>
<p className="text-gray-600">{comment.content}</p>
</div>
))}
</section>
);
}
async function RelatedPosts({ slug }: { slug: string }) {
const res = await fetch("/api/posts/" + slug + "/related");
const posts = await res.json();
return (
<aside className="mt-8">
<h2 className="text-xl font-semibold mb-4">Related Posts</h2>
{posts.map((post: Post) => (
<a key={post.id} href={"/posts/" + post.slug} className="block p-3 hover:bg-gray-50 rounded">
{post.title}
</a>
))}
</aside>
);
}
export default async function PostPage({ params }: { params: { slug: string } }) {
return (
<div className="max-w-3xl mx-auto">
<Suspense fallback={<PostSkeleton />}>
<PostContent slug={params.slug} />
</Suspense>
<Suspense fallback={<CommentsSkeleton />}>
<Comments postId={params.slug} />
</Suspense>
<Suspense fallback={<RelatedSkeleton />}>
<RelatedPosts slug={params.slug} />
</Suspense>
</div>
);
}
```
## Best Practices for Google Antigravity IDE
When using Suspense with Google Antigravity, wrap independent data in separate Suspense boundaries. Create meaningful skeleton components. Use parallel fetching for independent data. Stream critical content first. Let Gemini 3 generate Suspense boundaries from your component structure.
Google Antigravity excels at implementing progressive loading with Suspense.This 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.