SWR Introduction - React Data Fetching

beginner | 35 min read | 2025.12.14

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