React Query ilə Server State: Artıq useEffect Cəhənnəmində Yaşama
useEffect + useState ilə API çağırışları yazmaqdan yoruldun? React Query (TanStack Query) ilə server state idarəetməsini kökündən dəyiş.
React Query ilə Server State: Artıq useEffect Cəhənnəmində Yaşama
Bakıda bir frontend müsahibəyə gedirsən. HR sənə "Redux bilirsiniz?" deyir, sən "bəli" deyirsən. Sonra texniki müsahibədə senior developer soruşur: "Server state ilə client state arasındakı fərq nədir və niyə bunları eyni yerdə saxlamaq problemdir?" — və otaqda sükut çökür.
Bu məqalədə həmin suala cavab verəcəyik. Və cavab bir addan ibarətdir: React Query (indi rəsmi adı TanStack Query).
Problem: useEffect Cəhənnəmi
Bunu hamımız yazmışıq:
jsxconst [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { let cancelled = false; setLoading(true); fetch('/api/products') .then(res => res.json()) .then(json => { if (!cancelled) { setData(json); setLoading(false); } }) .catch(err => { if (!cancelled) { setError(err); setLoading(false); } }); return () => { cancelled = true; }; }, []);
3 dənə useState, 1 dənə useEffect, race condition üçün cancelled flag, error handling... Və bu bir endpoint üçündür. Layihədə 40 endpoint varsa nə baş verir? Cavab: xaos.
Bu pattern-in əsas problemləri:
- Caching yoxdur — hər component mount olanda yenidən fetch edir
- Stale data — istifadəçi tab-a qayıdanda köhnə data görür
- Deduplication yoxdur — eyni endpoint-ə 5 component eyni anda 5 request göndərir
- Loading/error state boilerplate — hər səhifədə eyni kodu yazırsan
Həll: React Query
React Query server state üçün xüsusi yaradılmış kitabxanadır. Client state (modal açıq/bağlı, form input-ları) üçün deyil — serverdən gələn data üçündür.
Quraşdırma:
bashnpm install @tanstack/react-query
Əvvəlcə provider qur:
jsximport { QueryClient, QueryClientProvider } from '@tanstack/react-query'; const queryClient = new QueryClient(); function App() { return ( <QueryClientProvider client={queryClient}> <YourApp /> </QueryClientProvider> ); }
İndi yuxarıdakı 15 sətirlik kodu 3 sətirə endirək:
jsximport { useQuery } from '@tanstack/react-query'; function Products() { const { data, isLoading, error } = useQuery({ queryKey: ['products'], queryFn: () => fetch('/api/products').then(res => res.json()), }); if (isLoading) return <Spinner />; if (error) return <ErrorMessage error={error} />; return ( <ul> {data.map(product => ( <li key={product.id}>{product.name} — {product.price} AZN</li> ))} </ul> ); }
Bu 3 sətirlik hook sənə nə verir:
- ✅ Avtomatik caching — eyni
queryKeyilə ikinci component mount olsa, cache-dən oxuyur - ✅ Background refetching — istifadəçi tab-a qayıdanda data sessiz yenilənir
- ✅ Deduplication — eyni anda 5 component eyni key istəsə, 1 request gedir
- ✅ Retry — request uğursuz olsa, avtomatik 3 dəfə təkrar cəhd edir
- ✅ Garbage collection — component unmount olandan 5 dəqiqə sonra cache təmizlənir
Real Ssenari: E-commerce Admin Panel
Tutaq ki, Bakıda bir startapda işləyirsən (məsələn, iş elanları və ya e-ticarət platforması) və admin paneldə sifarişləri idarə etməlisən. Sifariş siyahısını göstərmək, yeni sifariş əlavə etmək lazımdır.
Data çəkmək — useQuery
jsxfunction OrderList() { const { data: orders, isLoading } = useQuery({ queryKey: ['orders', { status: 'pending' }], queryFn: () => api.get('/orders?status=pending'), staleTime: 30 * 1000, // 30 saniyə ərzində yenidən fetch etmə refetchOnWindowFocus: true, // tab-a qayıdanda yenilə }); if (isLoading) return <TableSkeleton rows={10} />; return ( <table> <thead> <tr><th>ID</th><th>Müştəri</th><th>Məbləğ</th></tr> </thead> <tbody> {orders.map(order => ( <tr key={order.id}> <td>#{order.id}</td> <td>{order.customerName}</td> <td>{order.total} AZN</td> </tr> ))} </tbody> </table> ); }
Data dəyişmək — useMutation
Mutation — POST, PUT, DELETE əməliyyatları üçündür:
jsximport { useMutation, useQueryClient } from '@tanstack/react-query'; function CreateOrder() { const queryClient = useQueryClient(); const mutation = useMutation({ mutationFn: (newOrder) => api.post('/orders', newOrder), onSuccess: () => { // Sifariş yaradıldıqdan sonra siyahını yenilə queryClient.invalidateQueries({ queryKey: ['orders'] }); }, }); const handleSubmit = (formData) => { mutation.mutate({ customerName: formData.name, total: formData.amount, }); }; return ( <form onSubmit={handleSubmit}> {/* form fields */} <button disabled={mutation.isPending}> {mutation.isPending ? 'Göndərilir...' : 'Sifariş yarat'} </button> {mutation.isError && <p>Xəta baş verdi, yenidən cəhd et</p>} </form> ); }
invalidateQueries çağırıldıqda React Query avtomatik olaraq ['orders'] key-li bütün query-ləri yenidən fetch edir. Əllə heç nə yazmağa ehtiyac yoxdur.
staleTime vs gcTime (cacheTime)
Bu iki konsepti qarışdıranlar çoxdur:
| Parametr | Defolt | Nə edir |
|---|---|---|
staleTime | 0 | Data nə qədər "təzə" sayılır. 0 = hər zaman stale |
gcTime | 5 dəqiqə | Inactive query cache-dən nə zaman silinir |
Praktiki məsləhət: API-n çox dəyişmirsə (məsələn, kateqoriya siyahısı), staleTime: 10 * 60 * 1000 (10 dəqiqə) qoy. Lazımsız request-lər azalacaq, UX sürətlənəcək.
DevTools — Ən yaxşı dostun
React Query-nin öz DevTools-u var və bu, debug üçün əvəzsizdir:
bashnpm install @tanstack/react-query-devtools
jsximport { ReactQueryDevtools } from '@tanstack/react-query-devtools'; function App() { return ( <QueryClientProvider client={queryClient}> <YourApp /> <ReactQueryDevtools initialIsOpen={false} /> </QueryClientProvider> ); }
Browser-da aşağı sol küncdə çiçək ikonu görəcəksən. Onu açsan, bütün query-lərin statusunu — fresh, stale, fetching, inactive — real vaxtda görəcəksən. Müsahibədə bunu bilmək xal qazandırır.
Rəqəmlərlə danışaq
npm tendensiyalarına görə, @tanstack/react-query həftədə 4.5 milyondan çox yüklənir (mart 2026). GitHub-da 43,000+ star var. Stack Overflow Developer Survey 2025-ə görə, React developer-lərin 38%-i artıq layihələrində TanStack Query istifadə edir.
Bakı kontekstinə gəlsək: LinkedIn-dəki iş elanlarına baxsanız, ABB, Kapital Bank texnoloji komandaları, Pasha Holding-in digital layihələri, aicgroup.az kimi şirkətlər artıq React ekosistemində işləyir. "TanStack Query" və ya "React Query" bilmək, 2000-3500 AZN diapazonundakı frontend maaşlarına namizəd olarkən sizi fərqləndirən bacarıqlardan biridir.
Redux ilə müqayisə — nə vaxt nə istifadə etməli?
- Server state (API data, sifariş siyahısı, istifadəçi profili) → React Query
- Client state (modal açıq/bağlı, sidebar vəziyyəti, form state) → Zustand və ya Redux Toolkit
Bir çox layihədə Redux-un 70%-i server state üçün istifadə olunurdu. React Query ilə o 70%-i silə bilərsən. Nəticədə store sadələşir, boilerplate azalır, developer experience artır.
Yekun məsləhətlər
- Yeni layihəyə başlayırsan? — React Query-ni 1-ci gündən qur
- Mövcud layihədə Redux-da API çağırışların var? — tədricən miqrasiya et, bir endpoint ilə başla
- queryKey-ləri düzgün strukturlaşdır —
['orders', { status, page }]kimi nested key-lər istifadə et - staleTime-ı layihəyə uyğun tənzimlə — hər şey üçün defolt 0 saxlama
- DevTools-u development-də həmişə aktiv saxla
React Query öyrənmək bir axşama başa gəlir, amma layihəndəki kodu həftələrlə sadələşdirir. Bu gün npm install @tanstack/react-query yaz və fərqi özün gör.
Kod yazmağa davam et, Baku Stack seninlədir. 🚀
Oxşar məqalələr
React-da Performans: useMemo və useCallback — Nə Vaxt Lazımdır?
useMemo və useCallback hər yerə yazmaq reflex olub? Gəl birlikdə anlayaq: bu hook-lar nə vaxt həqiqətən lazımdır, nə vaxt isə əksinə — zərərdir.
React Query ilə Server State: useState-dən Qurtuluş Yolu
Hələ də API datanı useState + useEffect ilə idarə edirsən? React Query ilə server state-i necə peşəkar səviyyədə idarə etməyi öyrən.
React Server Components — Nə Vaxt İstifadə Etməli, Nə Vaxt Yox?
RSC hər yerə lazım deyil. Bu məqalədə real kod nümunələri ilə Server Components-in nə vaxt performans artırdığını, nə vaxt isə əngəl olduğunu izah edirik.