技能创建器
skill-creator
创建、改进和评估自定义技能,把专业流程转化为可重复使用的 AI 能力。
swr【数据与研究】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 `pi…
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
name: swr description: | 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"
pinia or composables; complex cache management - use tanstack-query; client state - use zustand
allowed-tools: Read, Grep, Glob, Write, EditDeep Knowledge: Use
mcp__documentation__fetch_docswith technology:swrfor comprehensive documentation.
npm install swr
| Scenario | Use Instead |
|---|---|
| Complex cache invalidation needs | tanstack-query for advanced features |
| Vue 3 applications | Composables with useFetch or useAsyncData |
| Client-side UI state | zustand or React state |
| GraphQL queries | @apollo/client or urql |
| Need offline support | tanstack-query with persist plugin |
| Anti-Pattern | Why It's Bad | Correct Approach |
|---|---|---|
| Using SWR for client state | Wrong abstraction, unnecessary complexity | Use Zustand or React state |
| Not providing global fetcher | Repetitive code, inconsistent error handling | Configure global fetcher in <SWRConfig> |
| Mutating without revalidation | Stale data shown to users | Call mutate() after updates |
| Fetching on every render | Performance issues, too many requests | Use stable key, leverage cache |
| Not handling error states | Poor UX, broken UI | Always check error property |
| Using different keys for same data | Cache fragmentation, duplication | Standardize key format across app |
| No loading states | Bad perceived performance | Use isLoading or isValidating |
| Manual cache updates everywhere | Hard to maintain | Use mutate() with optimistic updates |
Ignoring isValidating | Confusing UX during background refetch | Show subtle indicator when revalidating |
| Not using conditional fetching | Unnecessary requests | Pass null key when data not needed |
| Issue | Cause | Solution |
|---|---|---|
| Data not updating | revalidateOnFocus disabled | Enable in SWRConfig or use mutate() |
| "Cannot read property of undefined" | No loading check before accessing data | Add if (isLoading) return <Loading /> |
| Multiple requests for same key | No deduplication interval | Set dedupingInterval in config |
| Stale data after mutation | Not calling mutate() | Call mutate(key) or mutate() from hook |
| Memory leaks | SWR instance not cleaned up | Ensure proper component unmounting |
| TypeScript errors | No generic type | Use useSWR<DataType>(key, fetcher) |
| Infinite refetch loop | Key changes on every render | Use useMemo or stable key |
| 401 errors not handled | No global error handler | Configure error handler in <SWRConfig> |
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>;
}
import { SWRConfig } from 'swr';
function App() {
return (
<SWRConfig
value={{
fetcher: (url) => fetch(url).then(res => res.json()),
revalidateOnFocus: true,
dedupingInterval: 2000,
}}
>
<MyApp />
</SWRConfig>
);
}
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>;
}
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();
}
// Only fetch if userId exists
const { data } = useSWR(userId ? `/api/users/${userId}` : null, fetcher);
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>
</>
);
}
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>
);
}
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} />;
}
| Metric | Target |
|---|---|
| Cache hit ratio | > 80% |
| Average response time | < 200ms |
| Revalidation frequency | Appropriate for data freshness |
| Error rate | < 1% |
<SWRConfig>