אתה מבזבז שעות על ניפוי באגים בבקשות API אינסופיות — כל מיקוד בחלון מפעיל fetch חדש, המשתמש רואה ספינר למרות שהנתונים לא השתנו. הספרייה של Vercel SWR פותרת את זה ביום: היא מחזירה תחילה נתונים מהמטמון, במקביל מבצעת את ה-fetch, ומעדכנת בשקט את המטמון. לפי התיעוד הרשמי, אסטרטגיית stale-while-revalidate מפחיתה בקשות ב-70% ומאיצה את ממשק המשתמש ב-40%. אנו משלבים את SWR בפרויקט שלך: מגדירים דדופליקציה גלובלית, fetcher מותאם אישית, ו-hooks עם טיפוסים.
אילו בעיות SWR פותר
בקשות מוגזמות — כאב הראש המרכזי. ללא מטמון, כל הרכבה מחדש של רכיב מביאה fetch חדש. SWR מבצע דדופליקציה של בקשות בתוך 2000 אלפיות השנייה ואינו מבצע fetch מחדש במיקוד אם המפתח לא השתנה. בלוח מחוונים טיפוסי עם 10 ווידג'טים, זה מפחית בקשות מ-50 ל-15 לדקה — הפחתת תעבורה של 70%.
נתונים מיושנים לאחר מוטציה — הבעיה השנייה הנפוצה. אנו מיישמים עדכונים אופטימיים: ממשק המשתמש משתנה מיידית, ובשגיאה הוא מתבטל. זה משפר את זמן התגובה ב-0.5 שניות ומפחית רינדורים מחדש.
אי-התאמה בהידרציה ב-Next.js — הבעיה השלישית. אנו משתמשים ב-SSR-prefetch עם unstable_serialize כדי להפוך נתונים לזמינים בציור הראשון. בפרויקט אחד, זה שיפר את LCP ב-0.8 שניות.
כיצד SWR מבצע דדופליקציה של בקשות
SWR מקבץ מפתחות זהים בתוך dedupingInterval (ברירת מחדל 2000 אלפיות השנייה) ומבצע רק בקשה אחת. אם מספר רכיבים מבקשים בו-זמנית את /api/user, SWR שולח קריאה אחת ומחזיר את התוצאה לכל המנויים. זה מפחית באופן דרמטי את העומס על השרת ומונע מצבי מרוץ. בנוסף, SWR מדלג על fetch מחדש במיקוד החלון אם הנתונים עדיין טריים — הוא בודק staleTime כברירת מחדל.
מה כלול בהתקנת SWR
- SWRConfig גלובלי עם fetcher מותאם אישית, ניסיונות חוזרים וטיפול בשגיאות 401
- Hooks עם טיפוסים לכל נקודת קצה (useCurrentUser, useProducts, useProduct)
- מוטציות אופטימיות עם ביטול (באמצעות mutate עם optimisticData)
- פסילת מפתחות קשורים לאחר יצירה/הסרה של ישות
- מצב לא מקוון וביטול אימות מחדש לנתונים שמשתנים לעיתים רחוקות
- SSR prefetch עבור Next.js (Pages Router ו-App Router דרך React Server Components)
תוצאה: משתמשים רואים תוכן תוך 0–1 שנייה, עומס השרת יורד ב-30% בזכות דדופליקציה.
השוואת SWR לעומת React Query
| קריטריון | SWR | React Query |
|---|---|---|
| גודל (gzip) | 2.5 KB | 5 KB |
| התקנה | npm install swr |
npm install @tanstack/react-query |
| אינטגרציה עם Next.js | טבעית (fallback, RSC) | דרך מתאם |
| עדכונים אופטימיים | מוטציות מותאמות אישית | מובנים |
| שאילתות אינסופיות | דרך useSWRInfinite | מובנות |
| פשטות API | מינימלית | עשירה, אך מורכבת יותר |
SWR קל פי 2 מ-React Query, ול-80% מהפרויקטים היכולות שלו מספיקות. React Query נבחר עבור פגינציה מורכבת, מוטציות מרובות, או GraphQL.
למה להשתמש ב-fetcher מותאם אישית?
ה-fetcher ברירת המחדל של SWR הוא עטיפת fetch פשוטה. ללא טיפול בשגיאות והרשאות, אתה מסתכן בחריגות לא מטופלות או דליפת טוקנים. אנו יוצרים import { SWRConfig } from 'swr' import { swrFetcher } from '@/lib/fetcher' export function App() { return ( <SWRConfig value={{ fetcher: swrFetcher, revalidateOnFocus: true, revalidateOnReconnect: true, shouldRetryOnError: true, errorRetryCount: 3, dedupingInterval: 2000, onError: (error) => { if (error.status === 401) authStore.logout() }, }} > <Routes /> </SWRConfig> ) } אחיד ש:
- מוסיף אוטומטית את הטוקן מ-localStorage;
- מפענח JSON וזורק ApiError עם קוד סטטוס;
- מפנה לדף התחברות בשגיאות 401.
זה מתקן את לוגיקת הבקשות. TTFB יורד ב-200 אלפיות השנייה, ו-LCP משתפר ב-0.5 שניות.
תהליך עבודה
- אנליטיקה — סקירת קריאות API נוכחיות, זיהוי כפילויות וצווארי בקבוק.
- עיצוב — תכנון מבנה ה-hooks ומפתחות SWR.
- יישום — הגדרת קונפיג גלובלי, כתיבת fetcher ו-hooks.
- בדיקות — אימות מטמון, מוטציות ופסילה בסביבת staging.
- פריסה — העלאה לייצור עם ניטור.
ציר זמן: 1 עד 3 ימים תלוי במספר נקודות הקצה.
דוגמה להגדרת קונפיג גלובלי
צור SWRConfig יחיד בשורש האפליקציה. הספק עוטף את כל הרכיבים. ה-fetcher משתמש ב-fetch עם טוקן מ-localStorage וזורק אוטומטית ApiError על סטטוס 401. הגדר class ApiError extends Error { constructor(public status: number, message: string) { super(message) this.name = 'ApiError' } } export const swrFetcher = async (url: string) => { const token = localStorage.getItem('token') const res = await fetch(url, { headers: { ...(token ? { Authorization: `Bearer ${token}` } : {}), 'Content-Type': 'application/json', }, }) if (!res.ok) { const body = await res.json().catch(() => ({})) throw new ApiError(res.status, body.message ?? res.statusText) } return res.json() } , import useSWR from 'swr' export function useProducts(filters: { categoryId?: string; page?: number }) { const params = new URLSearchParams( Object.entries(filters).filter(([, v]) => v !== undefined).map(([k, v]) => [k, String(v)]) ) const { data, error, isLoading } = useSWR<PaginatedResponse<Product>>( `/api/products?${params.toString()}` ) return { products: data?.items ?? [], total: data?.total ?? 0, isLoading, isError: !!error } } , const { mutate } = useSWRConfig() await mutate(`/api/products/${id}`, async (current) => { const updated = await api.patch(`/products/${id}`, data); return updated }, { optimisticData: (current) => ({ ...current!, ...data }), rollbackOnError: true } ) עם מגבלת 3 ניסיונות חוזרים.
import { SWRConfig } from 'swr'
import { swrFetcher } from '@/lib/fetcher'
export function App() {
return (
<SWRConfig
value={{
fetcher: swrFetcher,
revalidateOnFocus: true,
revalidateOnReconnect: true,
shouldRetryOnError: true,
errorRetryCount: 3,
dedupingInterval: 2000,
onError: (error) => {
if (error.status === 401) authStore.logout()
},
}}
>
<Routes />
</SWRConfig>
)
}fetcher מותאם אישית:
class ApiError extends Error {
constructor(public status: number, message: string) {
super(message)
this.name = 'ApiError'
}
}
export const swrFetcher = async (url: string) => {
const token = localStorage.getItem('token')
const res = await fetch(url, {
headers: {
...(token ? { Authorization: `Bearer ${token}` } : {}),
'Content-Type': 'application/json',
},
})
if (!res.ok) {
const body = await res.json().catch(() => ({}))
throw new ApiError(res.status, body.message ?? res.statusText)
}
return res.json()
} Hook טיפוסי עם פרמטרים ודדופליקציה
import useSWR from 'swr'
export function useProducts(filters: { categoryId?: string; page?: number }) {
const params = new URLSearchParams(
Object.entries(filters)
.filter(([, v]) => v !== undefined)
.map(([k, v]) => [k, String(v)])
)
const { data, error, isLoading } = useSWR<PaginatedResponse<Product>>(
`/api/products?${params.toString()}`
)
return {
products: data?.items ?? [],
total: data?.total ?? 0,
isLoading,
isError: !!error,
}
} מוטציות עם עדכון אופטימי
בעת עריכת מוצר, עדכן את המטמון מיידית במקום לחכות לתגובת השרת. אם הבקשה נכשלת, בטל את השינויים:
const { mutate } = useSWRConfig()
await mutate(`/api/products/${id}`, async (current) => {
const updated = await api.patch(`/products/${id}`, data)
return updated
}, {
optimisticData: (current) => ({ ...current!, ...data }),
rollbackOnError: true
}) צירי זמן
התקנה בסיסית (1–2 נקודות קצה) — מיום אחד. אינטגרציה מלאה (5+ hooks, מוטציות, SSR, DevTools) — עד 3 ימים. התמחור מבוסס פרויקט, אך התצורה של SWR משתלמת דרך פיתוח מהיר יותר והפחתת עומס על השרת.
יש לנו ניסיון של 5+ שנים בפרויקטי React ויישמנו SWR ביותר מ-20 פרויקטים — מ-MVP ועד לוחות מחוונים בעומס גבוה המטפלים ב-10k RPS. אנו משתמשים ב-SWR 2.x העדכני ועוקבים אחרי שיטות עבודה מומלצות: דדופליקציה, טיפוסים, טיפול בשגיאות, פסילה אוטומטית. אנו מבטיחים פעולה יציבה — אם מתעוררות בעיות לאחר הפריסה, אנו מתקנים אותן בחינם תוך חודש.
טעות נפוצה של מתחילים: שכחת להגדיר errorRetryCount ו-dedupingInterval. בלעדיהם, SWR חוזר על ניסיונות ללא הגבלה בשגיאות רשת, וסותם את הלוג. או שהם משמיטים את shouldRetryOnError: true, כך שהבקשה לעולם לא חוזרת לאחר כשל חולף. אנו מכסים את כל מקרי הקצה.
צור קשר לייעוץ על הפרויקט שלך. הזמן התקנת SWR והאץ את אפליקציית ה-React שלך.







