Кешування в Next.js
Кешування в Next.js є однією з найскладніших і найчастіше обговорюваних тем на співбесідах. Next.js використовує чотири рівні кешування, кожен з яких працює на своєму етапі.
Чотири рівні кешування
Мемоізація запитів (сервер, під час рендерингу)
Дедуплікація ідентичних запитів на отримання даних в межах одного проходу рендерингу. Якщо кілька компонентів запитують однакові дані, запит виконується лише один раз.
Кеш даних (сервер, між запитами)
Кешує результати запитів на отримання даних між запитами користувачів і розгортаннями. Працює як CDN для даних.
Кеш повного маршруту (сервер, між запитами)
Кешує згенерований HTML та RSC Payload статичних маршрутів під час складання.
Кеш маршрутизатора (клієнт, під час сесії)
Кешує RSC Payload відвіданих маршрутів у браузері. Повернення назад відбувається миттєво.
Мемоізація запитів
React автоматично мемоізує запити на отримання даних з однаковим URL та параметрами:
// Обидва компоненти викликають один і той же запит
// Запит виконується лише один раз
async function Header() {
const user = await fetch('/api/user').then(r => r.json())
return <div>{user.name}</div>
}
async function Sidebar() {
const user = await fetch('/api/user').then(r => r.json())
return <div>{user.avatar}</div>
}Це працює лише під час одного проходу рендерингу на сервері. Для запитів ORM (Prisma, Drizzle) використовуйте React.cache:
import { cache } from 'react'
import { db } from '@/lib/db'
export const getUser = cache(async (id: string) => {
return db.user.findUnique({ where: { id } })
})Кеш даних
За замовчуванням fetch в Next.js кешує результат у Кеші даних:
// Кешується безстроково (до повторної валідації)
const res = await fetch('https://api.itlead.org/docs')
// Повторна валідація через 5 хвилин
const res = await fetch('https://api.itlead.org/problems', {
next: { revalidate: 300 }
})
// Без кешування
const res = await fetch('https://api.itlead.org/feed', {
cache: 'no-store'
})Повторна валідація
Два способи оновлення Кешу даних:
Часовий: дані вважаються застарілими після N секунд
const res = await fetch(url, { next: { revalidate: 60 } })Подієвий: явна інвалідизація через теги
// Під час отримання
const res = await fetch(url, { next: { tags: ['problems'] } })
// Під час оновлення даних (в Server Action)
import { revalidateTag } from 'next/cache'
revalidateTag('problems')Кеш повного маршруту
Статичні маршрути кешуються повністю під час складання. Цей кеш включає HTML та RSC Payload.
Маршрут є статичним, якщо він:
- Не використовує динамічні функції (
cookies(),headers(),searchParams) - Усі запити на отримання даних кешуються
Маршрут є динамічним, якщо він:
- Використовує
cookies(),headers()абоsearchParams - Має запит з
cache: 'no-store' - Встановлює
export const dynamic = 'force-dynamic'
Кеш маршрутизатора
Браузер кешує RSC Payload відвіданих сторінок. Це дозволяє:
- Миттєве повернення назад до попередніх сторінок
- Попереднє завантаження сторінок при наведенні на
Link
import Link from 'next/link'
// Next.js автоматично попередньо завантажує цю сторінку
<Link href="/problems">Problems</Link>
// Попереднє завантаження можна вимкнути
<Link href="/problems" prefetch={false}>Problems</Link>Порада для співбесіди:
Кеш маршрутизатора часто викликає плутанину. Сторінка може показувати застарілі дані після мутації, оскільки кеш клієнта ще не оновився. Рішення: викликати router.refresh() або revalidatePath() в Server Action.
Вимкнення кешування
Щоб повністю вимкнути кешування для сегмента:
// app/dashboard/layout.tsx
export const dynamic = 'force-dynamic'
export const revalidate = 0Корисні ресурси
- nextjs.org/docs — Кешування
- Fetching, Caching and Revalidating
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.