RTK Query și alternativele
Server state în Redux, tag-uri, și comparația cu TanStack Query, SWR, Apollo, RSC.
Actualizat
Ce este RTK Query
RTK Query e partea din Redux Toolkit care se ocupă de server state: aduce date de la API, le ține în cache, deduplică request-urile, gestionează loading/error și reîmprospătează automat după mutații. E echivalentul lui TanStack Query, dar construit peste Redux.
Ideea: nu mai scrii useEffect + fetch + useState pentru loading + reducer pentru date. Descrii endpoint-urile o singură dată, iar RTK Query generează hook-urile.
Un API complet
// shared/api/base-api.ts
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
export const api = createApi({
baseQuery: fetchBaseQuery({ baseUrl: '/api' }),
tagTypes: ['Post'],
endpoints: build => ({
getPosts: build.query<Post[], { page: number }>({
query: ({ page }) => `posts?page=${page}`,
providesTags: result => [
...(result ?? []).map(p => ({ type: 'Post' as const, id: p.id })),
{ type: 'Post', id: 'LIST' },
],
}),
addPost: build.mutation<Post, NewPost>({
query: body => ({ url: 'posts', method: 'POST', body }),
invalidatesTags: [{ type: 'Post', id: 'LIST' }],
}),
}),
})
export const { useGetPostsQuery, useAddPostMutation } = api'use client'
const { data, isLoading, error } = useGetPostsQuery({ page })
const [addPost, { isLoading: saving }] = useAddPostMutation()Tag-urile — cum știe ce să reîmprospăteze
| Concept | Rol |
|---|---|
tagTypes |
categoriile de date: 'Post', 'User' |
providesTags |
un query declară ce date conține: { type: 'Post', id: 1 } |
invalidatesTags |
o mutație declară ce date a schimbat |
| rezultat | query-urile cu tag-uri invalidate sunt re-cerute automat |
{ type: 'Post' } fără id invalidează toate postările; { type: 'Post', id: 1 } doar postarea 1. E același principiu ca cacheTag / updateTag din Next și queryKey / invalidateQueries din TanStack Query.
Alternativele — comparație
| RTK Query | TanStack Query | SWR | Apollo / urql | Server Components | |
|---|---|---|---|---|---|
| Pentru | REST / orice | REST / orice | REST / orice | GraphQL | orice, pe server |
| Depinde de | Redux | nimic | nimic | GraphQL | Next / RSC |
| Cache identificat prin | endpoint + argumente, tag-uri | queryKey |
cheia (URL) | tip + id (normalizat) | 'use cache' + cacheTag |
| Invalidare | tag-uri, declarativ | invalidateQueries |
mutate(key) |
automată după tip/id | updateTag / revalidateTag |
| Mărime | mare (cu Redux) | medie | mică | mare | 0 KB pe client |
| Când | ai deja Redux | implicit pe client | nevoi simple, Vercel-style | API GraphQL | implicit în Next pentru afișare |
Recomandarea practică:
- În Next.js App Router, începe cu Server Components pentru date afișate și Server Actions pentru mutații.
- Ai nevoie de date vii pe client (polling, infinite scroll, dashboard) → TanStack Query.
- Proiectul folosește deja Redux → RTK Query, ca să nu ai două sisteme.
- API GraphQL → Apollo sau urql.
Greșeli frecvente
- Să copiezi rezultatul unui query într-un slice Redux sau în
useState— două surse de adevăr. - Tag-uri lipsă → după o mutație, lista nu se actualizează.
- Un singur
createApiper aplicație; endpoint-urile se adaugă cuinjectEndpointsdin fiecare feature.
Pe scurt
- RTK Query = server state peste Redux; endpoint-uri → hook-uri generate.
providesTags+invalidatesTags= reîmprospătare automată după mutații.- Alternative: TanStack Query (implicit pe client), SWR (simplu), Apollo (GraphQL), Server Components (Next).