install
source · Clone the upstream repo
git clone https://github.com/ComeOnOliver/skillshub
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/ComeOnOliver/skillshub "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/TerminalSkills/skills/swr" ~/.claude/skills/comeonoliver-skillshub-swr && rm -rf "$T"
manifest:
skills/TerminalSkills/skills/swr/SKILL.mdsource content
SWR
Overview
SWR (stale-while-revalidate) is a React data fetching library — show cached data instantly, then revalidate in the background. Built by Vercel, it handles caching, deduplication, revalidation on focus/reconnect, pagination, and optimistic updates. Simpler than TanStack Query for straightforward data fetching, with a smaller API surface.
When to Use
- Fetching API data in React components
- Need instant page loads with background revalidation
- Real-time data that should refresh automatically
- Paginated or infinite scroll data
- Simpler alternative to TanStack Query for most use cases
Instructions
Setup
npm install swr
Basic Data Fetching
// hooks/useUser.ts — Fetch and cache user data import useSWR from "swr"; const fetcher = (url: string) => fetch(url).then((r) => r.json()); export function useUser(userId: string) { const { data, error, isLoading, mutate } = useSWR( `/api/users/${userId}`, fetcher, ); return { user: data, isLoading, isError: error, mutate, // Manually revalidate }; } // Usage in component function UserProfile({ userId }) { const { user, isLoading } = useUser(userId); if (isLoading) return <div>Loading...</div>; return <div>{user.name}</div>; }
Global Configuration
// app/providers.tsx — Global SWR config import { SWRConfig } from "swr"; const fetcher = async (url: string) => { const res = await fetch(url); if (!res.ok) throw new Error("API error"); return res.json(); }; export function Providers({ children }) { return ( <SWRConfig value={{ fetcher, revalidateOnFocus: true, // Refresh when tab regains focus revalidateOnReconnect: true, // Refresh when internet reconnects dedupingInterval: 2000, // Dedupe requests within 2s errorRetryCount: 3, }} > {children} </SWRConfig> ); }
Mutation and Optimistic Updates
// components/TodoList.tsx — Optimistic updates import useSWR, { useSWRConfig } from "swr"; function TodoList() { const { data: todos, mutate } = useSWR("/api/todos"); const addTodo = async (title: string) => { const newTodo = { id: Date.now(), title, done: false }; // Optimistic update — show immediately, revalidate in background await mutate( async () => { await fetch("/api/todos", { method: "POST", body: JSON.stringify({ title }), }); // Return updated data (or let SWR refetch) }, { optimisticData: [...(todos || []), newTodo], rollbackOnError: true, // Revert if API fails revalidate: true, // Refetch after mutation } ); }; }
Pagination
// components/PostList.tsx — Paginated data import useSWR from "swr"; function PostList() { const [page, setPage] = useState(1); const { data, isLoading } = useSWR(`/api/posts?page=${page}&limit=20`); return ( <div> {data?.posts.map((post) => <PostCard key={post.id} post={post} />)} <button onClick={() => setPage(page - 1)} disabled={page <= 1}>Previous</button> <button onClick={() => setPage(page + 1)} disabled={!data?.hasMore}>Next</button> </div> ); }
Infinite Loading
// components/InfiniteFeed.tsx — Infinite scroll import useSWRInfinite from "swr/infinite"; function InfiniteFeed() { const { data, size, setSize, isLoading } = useSWRInfinite( (index) => `/api/feed?page=${index + 1}&limit=20`, ); const posts = data?.flatMap((page) => page.posts) || []; const hasMore = data?.[data.length - 1]?.hasMore; return ( <div> {posts.map((post) => <PostCard key={post.id} post={post} />)} {hasMore && ( <button onClick={() => setSize(size + 1)} disabled={isLoading}> Load More </button> )} </div> ); }
Examples
Example 1: Dashboard with auto-refreshing data
User prompt: "Build a dashboard that shows live metrics — refresh every 5 seconds."
The agent will use SWR with
refreshInterval: 5000, show cached data instantly on mount, and handle loading/error states.
Example 2: CRUD with optimistic updates
User prompt: "Build a todo app where adding/deleting feels instant."
The agent will use SWR mutations with optimistic data, rollback on error, and automatic revalidation after changes.
Guidelines
- Key = cache key — same key = same cached data across components
key skips fetching — conditional fetching:nulluseSWR(userId ? /api/... : null)- Revalidation on focus — data refreshes when user returns to tab
- Optimistic updates — show changes immediately, revert on error
for cache updates — bound (per-key) or globalmutate
for infinite scroll — accumulates pagesuseSWRInfinite- Deduplication — multiple components using same key = one request
- Error retry built-in — automatic with exponential backoff
- Smaller than TanStack Query — simpler API for simpler needs
- Works with any fetcher — fetch, axios, GraphQL clients