# Što ovaj vodič pokriva#
React Query je jednostavno krenuti koristiti, a varljivo teško skalirati. Kako aplikacija raste, timovi obično nalete na iste probleme: široke invalidacije koje pokreću over-fetching, cachevi paginacije koji “odlutaju”, optimistična ažuriranja koja pucaju uz konkurentnost i zastarjeli UI koji tiho narušava povjerenje korisnika.
Ovaj vodič fokusira se na najbolje prakse invalidacije cachea u React Queryju i skalabilne obrasce za dizajn query keyjeva, ciljanu invalidaciju, paginaciju i infinite queryje, obrasce mutacija s optimističnim ažuriranjima te pozadinski refetch u stvarnim produkcijskim aplikacijama. Primjeri ciljaju Next.js App Router s client komponentama.
Ako odlučujete između biblioteka za dohvat podataka u App Routeru, pročitajte React Query vs SWR u Next.js App Routeru. Ako vas zanima kako se React Query uklapa s cachingom platforme, pogledajte Next.js strategije cachinga: SSR, ISR, SWR.
# Preduvjeti#
| Zahtjev | Verzija | Napomene |
|---|---|---|
| React | 18+ | Potrebno za App Router i ponašanje uz konkurentnost |
| Next.js | 14+ | Primjeri za App Router pretpostavljaju moderne routing konvencije |
| TanStack Query | 5+ | Obrasci i API-ji za React Query v5 |
| Osnovni REST ili GraphQL API | — | Primjeri koriste REST-slične endpointove |
| TypeScript | Preporučeno | Puno pomaže oko sigurnosti query keyjeva |
# Problem skaliranja: zašto invalidacija cachea postaje skupa#
React Query smanjuje mrežne pozive cachiranjem server statea. U velikim sustavima trošak se pomiče s “broja zahtjeva” na “predvidljivost ažuriranja”.
Tri stvarna failure modea se stalno ponavljaju:
- 1Over-fetching: jedna mutacija invalidira široke prefikse, refetchajući puno ekrana i trošeći API kvotu.
- 2Zastarjeli UI: korisnik nešto promijeni, mutacija uspije, ali neke liste i detail prikazi i dalje pokazuju stare podatke dok se ne dogodi slučajni refetch.
- 3Drift paginacije: paginirane liste i “countovi” se ne slažu, jer je ažuriran samo jedan cache entry.
Korisni mentalni model: server state u React Queryju je skup materijaliziranih prikaza (materialized views). Vaš posao je održavati te prikaze konzistentnima uz minimalan refetch.
🎯 Ključna poruka: U velikim aplikacijama cilj nije “nikad zastarjelo” niti “nikad refetch”. Cilj je predvidljiva svježina uz kontroliran opseg refetcha.
# Dizajn query keyjeva koji skalira#
Query keyjevi određuju identitet cachea. Dizajn ključeva je ono što kasnije omogućuje ciljanu invalidaciju. Ako ključeve postavite loše, kompenzirat ćete širokom invalidacijom, a široka invalidacija je mjesto gdje over-fetching počinje.
Pravila za produkcijske query keyjeve#
Primjenjujte ova pravila dosljedno kroz cijeli codebase:
- 1Hijerarhijski nizovi, ne stringovi.
- 2Stabilan poredak parametara u objektima, ili izbjegavajte objekte u keyjevima koristeći eksplicitne tupleove.
- 3Scope po tenant-u i authu kada je potrebno, da ne miješate cacheve.
- 4Odvojite “list” i “detail” ključeve kako biste mogli precizno ažurirati svako.
- 5Uključite filtre i sortiranje u list ključeve kako cachevi ne bi kolidirali.
Praktičan obrazac: factory za keyjeve#
Napravite jedan izvor istine za keyjeve po domeni. Time sprječavate “dovoljno slične” keyjeve koji kasnije razbijaju invalidaciju.
// queryKeys.ts
export const projectsKeys = {
all: ['projects'] as const,
lists: () => [...projectsKeys.all, 'list'] as const,
list: (params: { q?: string; status?: 'active' | 'archived'; page: number; pageSize: number }) =>
[...projectsKeys.lists(), params] as const,
details: () => [...projectsKeys.all, 'detail'] as const,
detail: (id: string) => [...projectsKeys.details(), id] as const,
};Ovaj dizajn vam omogućuje invalidaciju:
- jednog project detaila:
projectsKeys.detail(id) - svih project listi bez obzira na filtre:
projectsKeys.lists() - svega vezanog uz projekte:
projectsKeys.all
⚠️ Upozorenje: Izbjegavajte stavljati ne-serializable vrijednosti u query keyjeve, poput funkcija, klasa, Date objekata ili mutabilnih objekata. To može uzrokovati cache missove i duplirane zahtjeve koji izgledaju kao “React Query refetch-a nasumično”.
Multi-tenant i user-specific keyjevi#
Ako se podaci razlikuju po organizaciji ili korisniku, eksplicitno to navedite. Najčešći produkcijski bug je prikaz cacheiranih podataka druge organizacije nakon promjene organizacije.
| Scenarij | Primjer prefiksa ključa | Zašto je bitno |
|---|---|---|
| Single-tenant javni podaci | ['projects'] | Jednostavno i sigurno |
| Multi-tenant org podaci | ['org', orgId, 'projects'] | Sprječava miješanje cachea između organizacija |
| User-specific | ['me', userId, 'notifications'] | Izbjegava zastarjele podatke nakon promjene login-a |
| Role-based prikazi | ['org', orgId, 'admin', 'auditLogs'] | Izbjegava slučajno ponovno korištenje cachea |
# Najbolje prakse invalidacije cachea u React Queryju#
Invalidacija je poluga koja drži cache koherentnim. Zamka je invalidirati preširoko da bi se “bugovi prestali događati”, što povećava mrežni promet i čini aplikaciju nepredvidljivom.
Dajte prednost ciljanoj invalidaciji umjesto globalne invalidacije#
Mutacija treba invalidirati samo ono na što može utjecati. U praksi to znači invalidirati:
- detail cache mutiranog entiteta
- list cacheve gdje se taj entitet pojavljuje
- izvedene agregate koji ovise o njemu, poput countova i dashboarda
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { projectsKeys } from './queryKeys';
function useUpdateProject() {
const qc = useQueryClient();
return useMutation({
mutationFn: async (input: { id: string; name: string }) => {
const res = await fetch(`/api/projects/${input.id}`, {
method: 'PATCH',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ name: input.name }),
});
if (!res.ok) throw new Error('Failed to update project');
return (await res.json()) as { id: string; name: string };
},
onSuccess: (updated) => {
qc.setQueryData(projectsKeys.detail(updated.id), updated);
qc.invalidateQueries({ queryKey: projectsKeys.lists() });
},
});
}Ovaj obrazac je učinkovit jer:
- detail stranica odmah postaje konzistentna
- liste se refetchaju kako bi se uskladile sa serverovim poretkom, filtrima i izračunatim poljima
Kada je invalidacija preskupa#
Neke liste su preskupe za refetch pri svakoj mutaciji, npr.:
- teški search endpointovi
- analytics s više joinova
- spori third-party API-ji
U tim slučajevima, za hot path izravno ažurirajte cache, a refetchajte rjeđe.
Pristup:
- patchajte najvidljivije cacheve koristeći
setQueryData - zakazujte pozadinsko usklađivanje s
invalidateQueriesza uski podskup - koristite duži
staleTimeza teške queryje kako biste izbjegli ponavljani refetch
💡 Savjet: Ako imate rate limitove, pratite “refetch po mutaciji” kao KPI. U mnogim aplikacijama, samo sužavanje invalidacije s
['projects']naprojectsKeys.lists()smanji pozadinski refetch promet za 30 do 70 posto unutar tjedan dana, jer prestajete osvježavati nepovezane “detail” queryje i agregate.
Namjerno koristite djelomično podudaranje ključa#
React Query omogućuje invalidaciju po prefiksu. To je moćno i opasno.
| Poziv invalidacije | Opseg | Tipična upotreba |
|---|---|---|
invalidateQueries({ queryKey: projectsKeys.detail(id) }) | Jedan entity detail | Nakon ažuriranja tog entiteta |
invalidateQueries({ queryKey: projectsKeys.lists() }) | Sve varijante listi | Nakon create, delete, reorder |
invalidateQueries({ queryKey: projectsKeys.all }) | Sve u domeni | Rijetko, obično tijekom logouta ili velikog synca |
Ako vaš tim često poseže za projectsKeys.all, to je signal: nedostaje vam bolja struktura ključeva ili korak ažuriranja cachea.
# Obrasci paginacije koji ostaju konzistentni#
Paginacija uvodi više cacheva za “isti” dataset. Morate odlučiti što konzistentnost znači: po stranici, kroz stranice ili po skupu filtera.
Numerirana paginacija s keepPreviousData#
Za tablice i admin prikaze, numerirana paginacija je predvidljiva i podržava deep-linking. Zadržite prethodnu stranicu vidljivom dok se sljedeća učitava, kako UI ne bi treperio.
import { useQuery } from '@tanstack/react-query';
import { projectsKeys } from './queryKeys';
export function useProjectsPage(params: {
q?: string;
status?: 'active' | 'archived';
page: number;
pageSize: number;
}) {
return useQuery({
queryKey: projectsKeys.list(params),
queryFn: async () => {
const qs = new URLSearchParams({
q: params.q ?? '',
status: params.status ?? '',
page: String(params.page),
pageSize: String(params.pageSize),
});
const res = await fetch(`/api/projects?${qs.toString()}`);
if (!res.ok) throw new Error('Failed to load projects');
return (await res.json()) as { items: Array<{ id: string; name: string }>; total: number };
},
placeholderData: (prev) => prev,
staleTime: 30_000,
});
}Zašto je staleTime bitan: bez njega možete pokrenuti refetch petlje kad korisnici prebacuju tabove ili kad se komponente remountaju, što izgleda kao “spora paginacija”.
Kako uskladiti “total count” i “items”#
Ako vaš API vraća total, to postaje izvedena vrijednost u cacheu koja može “odlutati” nakon create ili delete. Odaberite jedno:
- Refetchajte liste na create ili delete, što je najjednostavnije.
- Ili ažurirajte totale u cacheu, što je brže, ali sklono greškama preko filtera.
Za većinu aplikacija, pouzdan pristup je: nakon create ili delete, invalidirajte prefiks liste i pustite server da ponovno izračuna totale.
# Infinite queryji za feedove i timelineove#
Infinite scrolling je najbolji za feedove gdje korisnici nastavljaju konzumirati sadržaj. Ključ je da query funkcija i getNextPageParam budu deterministični te da izbjegnete invalidiranje cijelog feeda pri svakoj maloj mutaciji.
Postavljanje infinite queryja#
import { useInfiniteQuery } from '@tanstack/react-query';
export function useActivityFeed(params: { projectId: string }) {
return useInfiniteQuery({
queryKey: ['projects', params.projectId, 'activity', 'infinite'],
queryFn: async ({ pageParam }) => {
const cursor = pageParam ? String(pageParam) : '';
const res = await fetch(`/api/projects/${params.projectId}/activity?cursor=${cursor}`);
if (!res.ok) throw new Error('Failed to load activity');
return (await res.json()) as {
items: Array<{ id: string; message: string; createdAt: string }>;
nextCursor: string | null;
};
},
initialPageParam: null as string | null,
getNextPageParam: (lastPage) => lastPage.nextCursor,
staleTime: 15_000,
});
}Strategija mutacija za infinite liste#
Izbjegavajte invalidirati cijeli infinite query ako dodajete samo jednu stavku. Primjerice, kod objave komentara ili activity itema:
- optimistično ubacite na početak stranice 1
- zatim invalidirajte samo ako server može presložiti stavke ili primijeniti moderation pravila
Ovo čini feed responzivnim i sprječava skupo ponašanje “reloadaj cijeli svijet”.
ℹ️ Napomena: Infinite queryji se često uparuju s cursor paginacijom. Ako vaš API koristi offset paginaciju za infinite scroll, brisanja i umetanja pomiču offsete i uzrokuju duplikate ili rupe. Cursor-based paginacija izbjegava tu klasu bugova.
# Obrasci mutacija za stvarne aplikacije#
Mutacije su mjesto gdje se UX i ispravnost cachea sudaraju. Skalabilan obrazac omogućuje korisniku trenutačnu povratnu informaciju uz jamstvo eventualne konzistentnosti.
Obrazac 1: Jednostavne mutacije sa setQueryData + invalidate#
Koristite kada:
- mutacija ažurira jedan entitet
- imate detail view koji mora odmah odražavati promjene
- liste se mogu refetchati u pozadini
Ovo smo već koristili u useUpdateProject. To je zadani obrazac za većinu CRUD-a.
Obrazac 2: Optimistična ažuriranja s rollbackom#
Optimistična ažuriranja koristite kada bi čekanje servera vidljivo pokvarilo UX, npr. toggleovi, lajkovi, zvjezdice (starring) ili promjena statusa u tablici.
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { projectsKeys } from './queryKeys';
export function useToggleArchived(projectId: string) {
const qc = useQueryClient();
return useMutation({
mutationFn: async (archived: boolean) => {
const res = await fetch(`/api/projects/${projectId}`, {
method: 'PATCH',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ archived }),
});
if (!res.ok) throw new Error('Failed to update');
return (await res.json()) as { id: string; archived: boolean; name: string };
},
onMutate: async (archived) => {
await qc.cancelQueries({ queryKey: projectsKeys.detail(projectId) });
const prev = qc.getQueryData<{ id: string; archived: boolean; name: string }>(
projectsKeys.detail(projectId)
);
qc.setQueryData(projectsKeys.detail(projectId), (current: any) =>
current ? { ...current, archived } : current
);
return { prev };
},
onError: (_err, _archived, ctx) => {
if (ctx?.prev) qc.setQueryData(projectsKeys.detail(projectId), ctx.prev);
},
onSettled: () => {
qc.invalidateQueries({ queryKey: projectsKeys.detail(projectId) });
qc.invalidateQueries({ queryKey: projectsKeys.lists() });
},
});
}Ključne točke:
- otkažite in-flight queryje da vaš optimistični patch ne bude prepisan
- napravite snapshot prethodnog stanja za rollback
- uvijek uskladite stanje nakon settle
Obrazac 3: Ažuriranje više cacheva bez refetchanja svega#
Ako se promijeni ime projekta, to utječe na:
- detail query
- svaku stranicu liste koja sadrži taj projekt
- cacheve rezultata pretraživanja
U tom slučaju može se isplatiti patchati list cacheve kako biste izbjegli refetch “oluju”.
Strategija:
- ažurirajte detail cache
- patchajte list cacheve koji su trenutno u memoriji iteriranjem kroz podudarne queryje
import { useQueryClient } from '@tanstack/react-query';
import { projectsKeys } from './queryKeys';
export function patchProjectNameEverywhere(qc: ReturnType<typeof useQueryClient>, input: { id: string; name: string }) {
qc.setQueryData(projectsKeys.detail(input.id), (p: any) => (p ? { ...p, name: input.name } : p));
const listQueries = qc.getQueriesData<{ items: Array<{ id: string; name: string }>; total: number }>({
queryKey: projectsKeys.lists(),
});
for (const [key, data] of listQueries) {
if (!data) continue;
qc.setQueryData(key, {
...data,
items: data.items.map((it) => (it.id === input.id ? { ...it, name: input.name } : it)),
});
}
}Ovo smanjuje mrežni promet i čini UI konzistentnim kroz otvorene tabove. Posebno je korisno u aplikacijama s čestim izmjenama.
# Pozadinski refetch bez živciranja korisnika#
Pozadinski refetch drži podatke svježima, ali default postavke mogu biti bučne u velikim aplikacijama. Najčešći simptom je “moja aplikacija zasipa zahtjevima kad se vratim na tab”.
Preporučeni defaulti za mnoge B2B aplikacije#
| Postavka | Tipična vrijednost | Zašto |
|---|---|---|
staleTime | 15 do 60 sekundi | Smanjuje refetch thrash na remount |
gcTime | 10 do 30 minuta | Drži nedavno korištene podatke u memoriji |
refetchOnWindowFocus | false za ne-kritične queryje | Sprječava focus “oluje” |
refetchOnReconnect | true | Dobar UX nakon prekida mreže |
retry | 1 do 2 | Izbjegava retry “oluje” tijekom ispada |
Konfigurirajte ovo u QueryClientu.
import { QueryClient } from '@tanstack/react-query';
export const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 30_000,
gcTime: 15 * 60_000,
refetchOnWindowFocus: false,
refetchOnReconnect: true,
retry: 1,
},
},
});Ako trebate drugačije ponašanje po queryju, overrideajte lokalno umjesto da sve držite na globalnom defaultu.
Kako izbjeći zastarjeli UI bez over-fetchinga#
Najčišći način da izbjegnete zastarjeli UI nije postaviti staleTime na nulu. Umjesto toga:
- Za kritične detail prikaze, držite
staleTimeumjerenim i refetchajte na navigaciju. - Nakon mutacija, uskladite stanje ciljanom invalidacijom.
- Koristite optimistična ažuriranja za trenutačan feedback.
- Za pozadinske dashboarde, postavite duži
staleTimei ponudite gumb za ručno osvježavanje.
To rezultira s manje zahtjeva i boljim doživljajem performansi.
# Next.js App Router: gdje se React Query uklapa#
App Router uvodi server komponente, route-level caching i semantiku cachiranja u fetchu. React Query je i dalje vrijedan, posebno za interaktivni, autentificirani, client-side server state.
Praktična arhitektura za App Router#
Koristite ovaj split:
- Server komponente obrađuju statične ili cacheable javne podatke, SEO stranice i početni skeleton.
- Client komponente koriste React Query za autentificirane podatke, interaktivne liste i mutacije.
Ako koristite i Next.js fetch caching, namjerno odaberite koji sloj “posjeduje” svježinu. Čest obrazac je:
- server fetch za initial render
- hidratizirati React Query s
initialDataza prvi ekran - pustiti React Query da preuzme daljnji refetch i mutacije
Primjer client komponente u App Routeru#
'use client';
import { useQuery } from '@tanstack/react-query';
import { projectsKeys } from './queryKeys';
export function ProjectDetailsClient({ id }: { id: string }) {
const q = useQuery({
queryKey: projectsKeys.detail(id),
queryFn: async () => {
const res = await fetch(`/api/projects/${id}`);
if (!res.ok) throw new Error('Failed to load project');
return (await res.json()) as { id: string; name: string; archived: boolean };
},
staleTime: 20_000,
});
if (q.isLoading) return 'Loading...';
if (q.isError) return 'Failed to load';
return q.data.name;
}Za širi kontekst cachiranja, povežite ovo s Next.js strategije cachinga: SSR, ISR, SWR. Bitno je izbjeći da se dva caching sustava međusobno “tuku” konfliktnim pravilima svježine.
# Observability: mjerite učinkovitost cachea, ne samo latenciju API-ja#
U velikim sustavima trebate feedback petlje. Problemi s invalidacijom cachea se manifestiraju kao:
- neočekivani skokovi API poziva nakon releaseova
- prijave korisnika tipa “spremilo se, ali i dalje vidim staru vrijednost”
- treperenje UI-ja ili loading stanja tijekom malih interakcija
Pratite barem ove metrike:
- stopu query zahtjeva po ruti
- broj mutacija i stopu grešaka mutacija
- prosječno vrijeme do svježih podataka nakon mutacije
- refetch-on-focus događaje po sesiji
Zatim korelirajte s logovima i traceovima. Tu observability postaje isplativ, posebno za distribuirane backendove i third-party API-je. Praktične upute za setup su u Vodič za observability web aplikacija: logovi, metrike, tracing.
💡 Savjet: Dodajte lagani client-side brojač za pozive
invalidateQueriespo korisničkoj sesiji. Ako skoči nakon releasea featurea, vjerojatno ste uveli široke invalidacije ili nestabilne query keyjeve.
# Česte zamke i kako ih izbjeći#
Zamka 1: Korištenje nestabilnih objekata u query keyjevima#
Ako u svakom renderu kreirate novi params objekt i on nije stabilan, možete stvoriti više cache entryja.
Rješenje:
- koristite key factory
- držite parametre minimalnima
- osigurajte stabilan poredak properties kada koristite objekte
Zamka 2: Preširoka invalidacija nakon svake mutacije#
Ako invalidirate ['projects'] nakon svakog ažuriranja projekta, refetchat ćete detail prikaze, liste, analitiku i sve ostalo pod tim prefiksom.
Rješenje:
- invalidirajte
detail(id)pluslists() - izravno ažurirajte cacheve za vidljive ekrane
Zamka 3: Invalidacija infinite queryja nakon svake male promjene#
Invalidiranje cijelog feeda nakon male akcije uništava korisnikov doživljaj performansi.
Rješenje:
- optimistični prepend ili patch
- usklađivanje ciljanim refetchom samo kada je nužno
Zamka 4: Oslanjanje na refetch-on-focus da “s vremenom popravi stanje”#
To stvara nekonzistentno ponašanje među browserima i navikama korisnika. Neki korisnici nikad ne napuste tab.
Rješenje:
- usklađujte nakon mutacija
- po potrebi odaberite eksplicitne intervale pozadinskog refetcha
# Ključne poruke#
- Dizajnirajte hijerarhijske, stabilne query keyjeve s domain key factoryjima kako bi invalidacija bila uska i predvidljiva.
- Kao default koristite ciljanu invalidaciju: invalidirajte entity detail plus relevantne list prefikse, ne cijelu domenu.
- Kombinirajte setQueryData s invalidateQueries u stvarnim aplikacijama: trenutačna konzistentnost UI-ja sada, usklađivanje sa serverom ubrzo nakon.
- Za paginaciju preferirajte keepPreviousData i invalidirajte list prefikse na create ili delete kako bi total ostao konzistentan.
- Koristite infinite queryje s cursor paginacijom i izbjegavajte invalidirati cijeli feed za male mutacije patchanjem stranice 1.
- Smanjite over-fetching razumnim defaultima za staleTime i refetch na fokus, a zatim utjecaj potvrdite kroz observability.
# Zaključak#
React Query dobro skalira kada invalidaciju cachea tretirate kao arhitektonsku odluku, a ne kao naknadnu misao. Stabilni query keyjevi, uska invalidacija i disciplinirani obrasci mutacija daju predvidljivu konzistentnost UI-ja bez pretvaranja svake korisničke akcije u refetch oluju.
Ako želite pomoć u primjeni ovih najboljih praksi invalidacije cachea u React Queryju u Next.js App Router codebaseu, Samioda može auditirati vaše query keyjeve i invalidation graf, smanjiti over-fetching i sigurno implementirati optimistična ažuriranja. Javite se putem samioda.com kako bismo razgovarali o data layeru vaše aplikacije.
FAQ
Osnivač i senior developer u Samiodi. 8+ godina iskustva u izradi React, Next.js, Flutter i n8n rješenja za klijente diljem Europe.
Više iz kategorije Web razvoj
Sve →React performanse u 2026.: profiliranje, memoizacija i obrasci renderiranja koji stvarno rade
Praktičan vodič korak po korak za profiliranje performansi i memoizaciju u Reactu u 2026.: kako dijagnosticirati spora sučelja uz React DevTools Profiler i why-did-you-render, odabrati prave obrasce renderiranja i izbjeći preuranjenu optimizaciju.
Next.js Edge Runtime vs Node.js Runtime (Vercel i Cloudflare): Što pokretati gdje
Praktičan okvir za odlučivanje između Next.js Edge Runtime i Node.js Runtime u 2026., s konkretnim primjerima, ograničenjima i završnom matricom use-caseova.
Server Actions u Next.js App Routeru: produkcijski obrasci za validaciju, greške i optimistični UI
Vodič spreman za produkciju za validaciju formi u Next.js Server Actions uz Zod, strukturirano rukovanje greškama, progresivno poboljšanje, optimistični UI i ograničavanje brzine — plus kada odabrati Server Actions umjesto API ruta.
Trebate pomoć s projektom?
Gradimo prilagođena rješenja koristeći tehnologije iz ovog članka. Senior tim, fiksne cijene.
Povezani članci
React Query vs SWR u Next.js App Routeru: Kada koristiti koji (i kako izbjeći dvostruko dohvaćanje)
Praktična usporedba za 2026. React Queryja i SWR-a unutar Next.js App Routera — modeli cacheiranja, SSR i RSC kompatibilnost, mutacije, optimistična ažuriranja, DX i provjereni obrasci za sprječavanje dvostrukog dohvaćanja.
Objašnjene strategije cacheiranja u Next.js-u: SSR, SSG, ISR, Route Cache i SWR
Praktičan vodič kroz Next.js strategije cacheiranja u eri App Routera — kako se SSR, SSG, ISR, Route Cache, Data Cache i SWR uklapaju u cjelinu, uz tablice za odluke, primjere koda i česte zamke poput zastarjelih auth i tenant podataka.
Kontrolni popis za migraciju na Next.js App Router (s Pages Routera) + česte zamke
Praktičan, korak-po-korak plan migracije na Next.js App Router s Pages Routera, uključujući kontrolni popis za routing, dohvat podataka, SEO metadata, deployment i vodič za rješavanje čestih zamki.