Dziennik / Rozwój produktów webowych
Jak działa pamięć podręczna w Next.js v13+ z Routerem aplikacji

Szczegółowe omówienie działania pamięci podręcznej w Next.js 13+, jakie rodzaje pamięci podręcznej istnieją, oraz jak wpływa to na wydajność i SEO.
Co to jest pamięć podręczna i jak działa w Next.js
Pamięć podręczna służy do przechowywania wyników obliczeń lub żądań, dzięki czemu nie trzeba ich powtarzać, co przyspiesza działanie aplikacji. W Next.js, strony HTML, dane, żądania, renderowanie komponentów oraz nawet całe trasy mogą być przechowywane w pamięci podręcznej.
Z wprowadzeniem Routera aplikacji (od Next.js 13) filozofia się zmieniła: pamięć podręczna jest teraz domyślnie włączona, a to od programisty zależy, czy ją wyłączyć, gdy potrzebne jest zachowanie dynamiczne.
Polityka Next.js jest następująca:
"Cachujemy wszystko, chyba że inaczej zasugerowano"
Jeśli nie określisz jawnie cache: 'no-store', next: { revalidate }, lub dynamic = 'force-dynamic', to:
fetch()będzie przechowywane w pamięci podręcznej- układ i strona mogą być również przechowywane w pamięci podręcznej
- trasy zostaną dodane do pamięci podręcznej trasy
- renderowanie strony przejdzie do pełnej pamięci podręcznej trasy
Zapewnia to wydajność, ale może prowadzić do przestarzałych danych i problemów z debugowaniem.
Rodzaje pamięci podręcznej w Next.js

Źródło: Dokumentacja Next.js
Pełna pamięć podręczna trasy (pamięć podręczna trasy po stronie serwera)
Używana z ISR (Inkrementalna Statyczna Regeneracja).
- Cała strona jest przechowywana w pamięci podręcznej (HTML, dane z
layout.tsx,page.tsx,fetch(),headers(),cookies()). - Pamięć podręczna znajduje się na serwerze.
- Działa domyślnie, gdy nie ma zachowania dynamicznego.
- Wyłączona za pomocą
revalidatelubrevalidateTag().
Najlepsza dla blogów, stron marketingowych i innych treści rzadko zmieniających się.
Przykład:
export const revalidate = 60; // regenerate the page every 60 seconds
Pamięć podręczna danych (pamięć podręczna pobierania danych po stronie serwera)
- Odpowiedzi z
fetch()w Komponentach Serwera są przechowywane w pamięci podręcznej. - Kontrolowana za pomocą
next: { revalidate }lubcache: 'no-store'.
Przykład:
await fetch('https://api.com/posts', {
next: { revalidate: 300 },
});
Memoizacja żądania (pamięć podręczna na żądanie, po stronie serwera)
Jest to optymalizacja wewnętrzna Next.js: ta sama fetch() lub funkcja z tymi samymi argumentami jest wywoływana tylko raz na renderowanie.
- W jednym renderowaniu serwera Next.js śledzi identyczne żądania.
- Jeśli zostały już wywołane, wynik jest pobierany z pamięci podręcznej.
- Działa niezależnie od
cache: 'force-cache'lubno-store.
Dobra dla:
- DRY (nie powtarzaj się) podczas pobierania tych samych danych w różnych komponentach.
- Poprawa wydajności bez konieczności manualnej optymalizacji.
- Gdy ten sam
fetchjest używany zarówno wlayout.tsxjak ipage.tsx.
Nie dla:
- Ponowne wykorzystanie między różnymi żądaniami lub użytkownikami (nie jest globalną pamięcią podręczną).
- Omijanie pamięci podręcznej pobierania danych - działa na bazie Memoizacji Żądań.
// lib/getUser.ts
export async function getUser() {
return fetch('https://api.com/user').then(res => res.json());
}
// app/layout.tsx
export default async function Layout({ children }) {
const user = await getUser(); // Call 1
return (
<div>
<Sidebar user={user} />
{children}
</div>
);
}
// app/page.tsx
import { getUser } from '../lib/getUser';
export default async function Page() {
const user = await getUser(); // Call 2, but actually not repeated
return <p>Hello, {user.name}</p>;
}
Fizycznie, fetch zostanie wywołany tylko raz, a wynik zostanie użyty w obu miejscach.
Pamięć podręczna routera (pamięć podręczna po stronie klienta)
To pamięć podręczna, którą kontrolujesz samodzielnie za pomocą bibliotek takich jak SWR, React Query i inne.
- Działa tylko z nawigacją po stronie klienta (
<Link>,router.push()). - Next.js nie kontroluje tej pamięci podręcznej — decydujesz, jak ją pamiętać.
- Bardzo szybka, ponieważ nic nie jest ponownie renderowane — React po prostu montuje z pamięci.
- Ale istnieje tylko do momentu, gdy użytkownik przeładuje stronę (F5).
Najlepsza dla interaktywnych komponentów, formularzy, pulpitów nawigacyjnych.
Przykład:
'use client';
import useSWR from 'swr';
const { data } = useSWR('/api/data', fetcher);
Wizualne porównanie rodzajów pamięci podręcznej
| Rodzaj pamięci podręcznej | Gdzie działa | Kontrola | Przykład |
|---|---|---|---|
| Pełna pamięć podręczna trasy | Serwer (cała trasa) | ponowna walidacja, tag | eksport const revalidate = 60 |
| Pamięć podręczna danych | Serwer (pobieranie) | pamięć podręczna, ponowna walidacja | pobierz(..., { next: ... }) |
| Pamięć podręczna generowana statycznie | Serwer (czas budowy) | Brak | JSX bez danych |
| Pamięć podręczna po stronie klienta | Przeglądarka / klient | Ty | SWR / React Query |
Przykład życia codziennego
Załóżmy, że budujesz sklep:
| Strona | Co zapamiętać | Jaki rodzaj pamięci podręcznej użyć |
|---|---|---|
/produkty | Lista produktów, aktualizacja co 5 minut | Pełna trasa pamięci podręcznej (ISR) |
/api/produkty | Dane API produktu | Pamięć podręczna danych (z revalidateTag) |
| Nawigacja SPA | Szybka nawigacja | Pamięć podręczna routera (pamięć podręczna po stronie klienta) |
Typowe problemy z pamięcią podręczną w aplikacji Router
Zaktualizowane dane — ale strona pokazuje stare dane
fetch() używa force-cache domyślnie, jeśli nie określisz cache: 'no-store' lub next: { revalidate }. W rezultacie Next.js zapamiętuje dane i nigdy ich nie aktualizuje.
Rozwiązanie:
- Dodaj
cache: 'no-store'aby wyłączyć buforowanie - Lub
next: { revalidate: 60 }dla ISR
fetch('https://api.com/data', { next: { revalidate: 60 } });
URL (searchParams) się zmienił, ale dane są takie same
Next.js nie ponownie generuje żądania pobierania, jeśli URL jest taki sam. Jeśli używasz parametrów, dodaj je bezpośrednio do adresu URL pobierania:
fetch(`https://api.com/posts?category=${searchParams.category}`, {
next: { revalidate: 60 }
});
Nawigacja za pomocą <Link>, ale dane się nie zaktualizowały
Pamięć podręczna routera (pamięć podręczna po stronie klienta) została użyta. Next.js nie wysyła nowego żądania podczas powrotu na stronę.
Rozwiązanie:
- Wymuś odświeżenie danych za pomocą
router.refresh() - Użyj
cache: 'no-store'jeśli dane muszą być zawsze świeże
revalidatePath() lub revalidateTag() nie działa
- Pamięć podręczna nie została utworzona (np. z powodu
no-store) - Nie używasz
tagóww pobieraniu - Wywołujesz
revalidatePath()poza akcją serwera
Rozwiązanie:
- Upewnij się, że pobieranie używa
next: { tags: [...] } - Wywołaj
revalidateTag('tag')w funkcji serwera
Układ jest buforowany i nie aktualizuje się
layout.tsx jest także buforowany jako RSC z revalidate, a jeśli dane wewnątrz są buforowane, nie zostaną zaktualizowane aż do następnego ISR.
Rozwiązanie:
- Użyj
cache: 'no-store'dla pobierania w layout.tsx, jeśli na przykład zawiera profil użytkownika - Albo przenieś pobieranie z układu do strony (lub komponentu klienta z SWR)
Niespodziewane zachowanie w trybie developerskim (dev)
W next dev, wiele pamięci podręcznej jest wyłączonych lub działa inaczej, a revalidate nie działa niezawodnie w trybie deweloperskim.
Wskazówka:
Przetestuj pamięć podręczną z kolejną kompilacją && uruchomieniem next lub podglądem Vercel.
Kombinacja cookies(), headers(), params i fetch() psuje pamięć podręczną.
Kiedy używasz dynamicznych rzeczy jak:
cookies()
headers()
useSearchParams()
generateMetadata() z dynamicznymi
Next.js automatycznie wyłącza pamięć podręczną strony i przełącza się na dynamic = 'force-dynamic'. Lista kontrolna: jak unikać problemów z pamięcią podręczną
Zawsze jasno ustawiaj zachowanie pobierania:
- Nie zapomnij o bezpośrednim uwzględnieniu parametrów zapytania w adresie URL pobierania
// no cache at all
fetch(..., { cache: 'no-store' })
// ISR (revalidate every 60 seconds)
fetch(..., { next: { revalidate: 60 } })
// manual invalidation via tag
fetch(..., { next: { tags: ['products'] } })
- Przetestuj z
- kolejną kompilacją && uruchomieniem next
— w przeciwnym razie możesz mieć fałszywe poczucie pewnościJeśli musisz ręcznie unieważnić dane, użyj - revalidatePath()
lubrevalidateTag()Jak działa pamięć podręczna w Next.js v13+ z App Router