What You’ll Learn in This Tutorial
✓ SWR basics
✓ Data fetching
✓ Mutations
✓ Cache control
✓ Revalidation
Step 1: Setup
npm install swr
Step 2: Basic Usage
import useSWR from 'swr';
const fetcher = (url: string) => fetch(url).then(res => res.json());
function Profile() {
const { data, error, isLoading } = useSWR('/api/user', fetcher);
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return <div>Hello, {data.name}</div>;
}
Step 3: Global Configuration
// app/providers.tsx
import { SWRConfig } from 'swr';
const fetcher = async (url: string) => {
const res = await fetch(url);
if (!res.ok) throw new Error('Failed to fetch');
return res.json();
};
export function Providers({ children }: { children: React.ReactNode }) {
return (
<SWRConfig
value={{
fetcher,
revalidateOnFocus: true,
revalidateOnReconnect: true,
dedupingInterval: 2000,
}}
>
{children}
</SWRConfig>
);
}
Step 4: Conditional Fetching
function UserPosts({ userId }: { userId: string | null }) {
// Don't fetch if userId is null
const { data } = useSWR(
userId ? `/api/users/${userId}/posts` : null
);
return <div>{/* ... */}</div>;
}
Step 5: Mutations
import useSWR, { useSWRConfig } from 'swr';
function UpdateProfile() {
const { mutate } = useSWRConfig();
const updateUser = async (newData: any) => {
await fetch('/api/user', {
method: 'PUT',
body: JSON.stringify(newData),
});
// Revalidate cache
mutate('/api/user');
};
return <button onClick={() => updateUser({ name: 'New Name' })}>Update</button>;
}
Step 6: Optimistic Updates
function TodoList() {
const { data, mutate } = useSWR('/api/todos');
const addTodo = async (text: string) => {
const newTodo = { id: Date.now(), text, completed: false };
// Optimistically update
mutate([...data, newTodo], false);
// API call
await fetch('/api/todos', {
method: 'POST',
body: JSON.stringify({ text }),
});
// Revalidate
mutate();
};
return (/* ... */);
}
Step 7: Pagination
import useSWRInfinite from 'swr/infinite';
function InfiniteList() {
const getKey = (pageIndex: number, previousPageData: any) => {
if (previousPageData && !previousPageData.length) return null;
return `/api/posts?page=${pageIndex}`;
};
const { data, size, setSize, isLoading } = useSWRInfinite(getKey);
const posts = data ? data.flat() : [];
const isLoadingMore = isLoading || (size > 0 && data && typeof data[size - 1] === 'undefined');
return (
<div>
{posts.map((post) => (
<div key={post.id}>{post.title}</div>
))}
<button
onClick={() => setSize(size + 1)}
disabled={isLoadingMore}
>
{isLoadingMore ? 'Loading...' : 'Load More'}
</button>
</div>
);
}
Step 8: Prefetching
import { preload } from 'swr';
// Prefetch on mouse hover
function UserCard({ userId }: { userId: string }) {
const handleMouseEnter = () => {
preload(`/api/users/${userId}`, fetcher);
};
return (
<a href={`/users/${userId}`} onMouseEnter={handleMouseEnter}>
View Profile
</a>
);
}
Summary
SWR is a lightweight data fetching library by Vercel. It automates caching and revalidation with the stale-while-revalidate strategy.
← Back to list