SWR - React hooks for data fetching with caching. Lightweight alternative to TanStack Query for simple data fetching needs. USE WHEN: user mentions "swr", "stale-while-revalidate", "useSWR", asks about "simple data fetching", "real-time data", "automatic revalidation", "lightweight caching", "vercel data fetching" DO NOT USE FOR: Vue apps - use `pinia` or composables; complex cache management - use `tanstack-query`; client state - use `zustand`

GitHub
安装命令
npx skhub add claude-dev-suite/swr
Markdown
SKILL.md

SWR Core Knowledge

Deep Knowledge: Use mcp__documentation__fetch_docs with technology: swr for comprehensive documentation.

Setup

npm install swr

When NOT to Use This Skill

ScenarioUse Instead
Complex cache invalidation needstanstack-query for advanced features
Vue 3 applicationsComposables with useFetch or useAsyncData
Client-side UI statezustand or React state
GraphQL queries@apollo/client or urql
Need offline supporttanstack-query with persist plugin

Anti-Patterns

Anti-PatternWhy It's BadCorrect Approach
Using SWR for client stateWrong abstraction, unnecessary complexityUse Zustand or React state
Not providing global fetcherRepetitive code, inconsistent error handlingConfigure global fetcher in <SWRConfig>
Mutating without revalidationStale data shown to usersCall mutate() after updates
Fetching on every renderPerformance issues, too many requestsUse stable key, leverage cache
Not handling error statesPoor UX, broken UIAlways check error property
Using different keys for same dataCache fragmentation, duplicationStandardize key format across app
No loading statesBad perceived performanceUse isLoading or isValidating
Manual cache updates everywhereHard to maintainUse mutate() with optimistic updates
Ignoring isValidatingConfusing UX during background refetchShow subtle indicator when revalidating
Not using conditional fetchingUnnecessary requestsPass null key when data not needed

Quick Troubleshooting

IssueCauseSolution
Data not updatingrevalidateOnFocus disabledEnable in SWRConfig or use mutate()
"Cannot read property of undefined"No loading check before accessing dataAdd if (isLoading) return <Loading />
Multiple requests for same keyNo deduplication intervalSet dedupingInterval in config
Stale data after mutationNot calling mutate()Call mutate(key) or mutate() from hook
Memory leaksSWR instance not cleaned upEnsure proper component unmounting
TypeScript errorsNo generic typeUse useSWR<DataType>(key, fetcher)
Infinite refetch loopKey changes on every renderUse useMemo or stable key
401 errors not handledNo global error handlerConfigure error handler in <SWRConfig>

Core Patterns

Basic Fetching

import useSWR from 'swr';

const fetcher = (url: string) => fetch(url).then(res => res.json());

function UserProfile({ userId }: { userId: string }) {
  const { data, error, isLoading } = useSWR(`/api/users/${userId}`, fetcher);

  if (error) return <div>Failed to load</div>;
  if (isLoading) return <div>Loading...</div>;
  return <div>Hello {data.name}!</div>;
}

Global Configuration

import { SWRConfig } from 'swr';

function App() {
  return (
    <SWRConfig
      value={{
        fetcher: (url) => fetch(url).then(res => res.json()),
        revalidateOnFocus: true,
        dedupingInterval: 2000,
      }}
    >
      <MyApp />
    </SWRConfig>
  );
}

Mutation

import useSWR, { mutate } from 'swr';

function UpdateUser() {
  const { data } = useSWR('/api/user', fetcher);

  async function handleUpdate() {
    await fetch('/api/user', {
      method: 'PUT',
      body: JSON.stringify({ name: 'New Name' })
    });

    // Revalidate the cache
    mutate('/api/user');
  }

  return <button onClick={handleUpdate}>Update</button>;
}

Optimistic Updates

const { data, mutate } = useSWR('/api/user', fetcher);

async function updateUser(newData: User) {
  // Optimistic update
  mutate({ ...data, ...newData }, false);

  // Send request
  await fetch('/api/user', {
    method: 'PUT',
    body: JSON.stringify(newData)
  });

  // Revalidate
  mutate();
}

Conditional Fetching

// Only fetch if userId exists
const { data } = useSWR(userId ? `/api/users/${userId}` : null, fetcher);

Pagination

function UserList() {
  const [page, setPage] = useState(1);
  const { data, isLoading } = useSWR(`/api/users?page=${page}`, fetcher);

  return (
    <>
      {data?.users.map(user => <UserCard key={user.id} user={user} />)}
      <button onClick={() => setPage(p => p + 1)}>Next</button>
    </>
  );
}

Production Readiness

Global Configuration

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();
};

function App() {
  return (
    <SWRConfig
      value={{
        fetcher,
        revalidateOnFocus: true,
        revalidateOnReconnect: true,
        shouldRetryOnError: true,
        errorRetryCount: 3,
        dedupingInterval: 2000,
        focusThrottleInterval: 5000,
        onError: (error) => {
          console.error('SWR Error:', error);
          if (error.status === 401) {
            // Redirect to login
          }
        },
      }}
    >
      <MyApp />
    </SWRConfig>
  );
}

Error Handling

function UserProfile({ userId }: { userId: string }) {
  const { data, error, isLoading } = useSWR<User, ApiError>(
    `/api/users/${userId}`,
    fetcher
  );

  if (error) {
    if (error.status === 404) return <NotFound />;
    if (error.status >= 500) return <ServerError />;
    return <ErrorMessage error={error} />;
  }

  if (isLoading) return <Skeleton />;

  return <UserCard user={data} />;
}

Monitoring Metrics

MetricTarget
Cache hit ratio> 80%
Average response time< 200ms
Revalidation frequencyAppropriate for data freshness
Error rate< 1%

Checklist

  • Global fetcher configured in <SWRConfig>
  • Error handling for all status codes
  • Loading states for all data fetches
  • Optimistic updates for mutations
  • Conditional fetching where appropriate
  • Stable cache keys (no render-time generation)
  • TypeScript types for all data
  • Retry logic configured
  • Focus revalidation enabled
  • Global error handler for auth failures

Reference Documentation

发现
标签

此技能尚未发布标签。

版本
最新版本元数据

版本

v2026.09.24

发布时间

2026年9月24日

分类

未分类

许可证

MIT

源路径

skills/state-management/swr

默认分支

main

最新提交

9496306

Tree SHA

fe4e2f1