Efficient data fetching with SWR including caching, revalidation, and optimistic updates for Google Antigravity.
# SWR Caching Strategies for Google Antigravity
SWR (stale-while-revalidate) provides powerful data fetching with automatic caching and revalidation. Google Antigravity's Gemini 3 helps you implement efficient data fetching strategies with intelligent caching patterns.
## SWR Configuration
Set up global SWR configuration:
```typescript
// lib/swr/config.tsx
"use client";
import { SWRConfig } from "swr";
const fetcher = async (url: string) => {
const res = await fetch(url);
if (!res.ok) {
const error = new Error("An error occurred while fetching the data.");
error.info = await res.json();
error.status = res.status;
throw error;
}
return res.json();
};
export function SWRProvider({ children }: { children: React.ReactNode }) {
return (
<SWRConfig
value={{
fetcher,
revalidateOnFocus: true,
revalidateOnReconnect: true,
dedupingInterval: 2000,
errorRetryCount: 3,
errorRetryInterval: 5000,
onError: (error, key) => {
if (error.status !== 403 && error.status !== 404) {
console.error(`SWR Error [${key}]:`, error);
}
},
}}
>
{children}
</SWRConfig>
);
}
```
## Basic Data Fetching
Implement simple data fetching hooks:
```typescript
// hooks/useUser.ts
import useSWR from "swr";
interface User {
id: string;
name: string;
email: string;
avatarUrl: string | null;
}
export function useUser(id?: string) {
const { data, error, isLoading, mutate } = useSWR<User>(
id ? `/api/users/${id}` : null
);
return {
user: data,
isLoading,
isError: !!error,
error,
mutate,
};
}
export function useCurrentUser() {
const { data, error, isLoading, mutate } = useSWR<User>("/api/users/me");
return {
user: data,
isLoading,
isError: !!error,
mutate,
};
}
```
## Pagination with SWR
Handle paginated data efficiently:
```typescript
// hooks/usePosts.ts
import useSWR from "swr";
import useSWRInfinite from "swr/infinite";
interface Post {
id: string;
title: string;
content: string;
createdAt: string;
}
interface PostsResponse {
data: Post[];
pagination: {
page: number;
limit: number;
total: number;
totalPages: number;
};
}
export function usePosts(page: number = 1, limit: number = 10) {
const { data, error, isLoading, mutate } = useSWR<PostsResponse>(
`/api/posts?page=${page}&limit=${limit}`
);
return {
posts: data?.data ?? [],
pagination: data?.pagination,
isLoading,
isError: !!error,
mutate,
};
}
export function useInfinitePosts(limit: number = 10) {
const getKey = (pageIndex: number, previousPageData: PostsResponse | null) => {
if (previousPageData && !previousPageData.data.length) return null;
return `/api/posts?page=${pageIndex + 1}&limit=${limit}`;
};
const { data, error, size, setSize, isValidating, mutate } =
useSWRInfinite<PostsResponse>(getKey);
const posts = data ? data.flatMap((page) => page.data) : [];
const isLoadingInitial = !data && !error;
const isLoadingMore =
isLoadingInitial || (size > 0 && data && typeof data[size - 1] === "undefined");
const isEmpty = data?.[0]?.data.length === 0;
const isReachingEnd =
isEmpty || (data && data[data.length - 1]?.data.length < limit);
return {
posts,
isLoading: isLoadingInitial,
isLoadingMore,
isReachingEnd,
isValidating,
size,
setSize,
mutate,
error,
};
}
```
## Optimistic Updates
Implement optimistic UI updates:
```typescript
// hooks/useTodos.ts
import useSWR, { mutate } from "swr";
interface Todo {
id: string;
title: string;
completed: boolean;
}
export function useTodos() {
const { data, error, isLoading } = useSWR<Todo[]>("/api/todos");
const addTodo = async (title: string) => {
const newTodo: Todo = {
id: `temp-${Date.now()}`,
title,
completed: false,
};
await mutate(
"/api/todos",
async (current: Todo[] | undefined) => {
const optimisticData = [...(current || []), newTodo];
const response = await fetch("/api/todos", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ title }),
});
if (!response.ok) {
throw new Error("Failed to create todo");
}
const createdTodo = await response.json();
return optimisticData.map((todo) =>
todo.id === newTodo.id ? createdTodo : todo
);
},
{
optimisticData: (current) => [...(current || []), newTodo],
rollbackOnError: true,
populateCache: true,
revalidate: false,
}
);
};
const toggleTodo = async (id: string) => {
await mutate(
"/api/todos",
async (current: Todo[] | undefined) => {
const todo = current?.find((t) => t.id === id);
if (!todo) return current;
const response = await fetch(`/api/todos/${id}`, {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ completed: !todo.completed }),
});
if (!response.ok) throw new Error("Failed to update todo");
const updated = await response.json();
return current?.map((t) => (t.id === id ? updated : t));
},
{
optimisticData: (current) =>
current?.map((t) =>
t.id === id ? { ...t, completed: !t.completed } : t
),
rollbackOnError: true,
populateCache: true,
revalidate: false,
}
);
};
const deleteTodo = async (id: string) => {
await mutate(
"/api/todos",
async (current: Todo[] | undefined) => {
const response = await fetch(`/api/todos/${id}`, {
method: "DELETE",
});
if (!response.ok) throw new Error("Failed to delete todo");
return current?.filter((t) => t.id !== id);
},
{
optimisticData: (current) => current?.filter((t) => t.id !== id),
rollbackOnError: true,
populateCache: true,
revalidate: false,
}
);
};
return {
todos: data ?? [],
isLoading,
isError: !!error,
addTodo,
toggleTodo,
deleteTodo,
};
}
```
## Conditional Fetching
Fetch data based on conditions:
```typescript
// hooks/useConditionalData.ts
import useSWR from "swr";
import { useAuth } from "@/contexts/AuthContext";
interface UserProfile {
id: string;
name: string;
settings: Record<string, unknown>;
}
export function useUserProfile() {
const { user, isLoading: authLoading } = useAuth();
const { data, error, isLoading, mutate } = useSWR<UserProfile>(
user ? `/api/users/${user.id}/profile` : null,
{
revalidateOnMount: true,
}
);
return {
profile: data,
isLoading: authLoading || isLoading,
isError: !!error,
mutate,
};
}
export function useUserPosts(userId?: string) {
const { data: user } = useSWR(userId ? `/api/users/${userId}` : null);
const { data: posts, isLoading } = useSWR(
user ? `/api/users/${userId}/posts` : null
);
return {
user,
posts: posts ?? [],
isLoading,
};
}
```
## Mutation Helpers
Create reusable mutation utilities:
```typescript
// lib/swr/mutations.ts
import { mutate } from "swr";
export async function createResource<T>(
url: string,
data: Partial<T>,
listKey: string
): Promise<T> {
const response = await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data),
});
if (!response.ok) {
throw new Error("Failed to create resource");
}
const created = await response.json();
mutate(listKey);
return created;
}
export async function updateResource<T>(
url: string,
data: Partial<T>,
listKey?: string
): Promise<T> {
const response = await fetch(url, {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data),
});
if (!response.ok) {
throw new Error("Failed to update resource");
}
const updated = await response.json();
mutate(url, updated, false);
if (listKey) {
mutate(listKey);
}
return updated;
}
export async function deleteResource(url: string, listKey?: string): Promise<void> {
const response = await fetch(url, {
method: "DELETE",
});
if (!response.ok) {
throw new Error("Failed to delete resource");
}
mutate(url, undefined, false);
if (listKey) {
mutate(listKey);
}
}
```
## Best Practices
1. **Use conditional fetching** - Pass null key to disable fetching
2. **Implement optimistic updates** - Update UI before API confirms
3. **Configure global settings** - Set defaults in SWRConfig
4. **Handle errors gracefully** - Use error boundaries and fallbacks
5. **Deduplicate requests** - SWR handles this automatically
SWR with Google Antigravity enables efficient data fetching with intelligent caching and revalidation strategies.This swr 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 swr 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 swr projects, consider mentioning your framework version, coding style, and any specific libraries you're using.