Кэширование и ревалидация данных

Кэширование — это техника хранения результатов запросов данных и других вычислений, чтобы последующие запросы тех же данных выполнялись быстрее, без повторного выполнения работы. Ревалидация позволяет обновлять записи в кэше без необходимости пересобирать всё приложение.

Next.js предоставляет несколько API для работы с кэшированием и ревалидацией. Это руководство покажет, когда и как их использовать.

fetch

По умолчанию запросы fetch не кэшируются. Вы можете кэшировать отдельные запросы, установив параметр cache в значение 'force-cache'.

export default async function Page() {
  const data = await fetch('https://...', { cache: 'force-cache' })
}
export default async function Page() {
  const data = await fetch('https://...', { cache: 'force-cache' })
}

Полезно знать: Хотя запросы fetch по умолчанию не кэшируются, Next.js будет предварительно рендерить маршруты с запросами fetch и кэшировать HTML. Если вы хотите гарантировать, что маршрут будет динамическим, используйте API connection.

Чтобы обновить данные, возвращаемые запросом fetch, можно использовать параметр next.revalidate.

export default async function Page() {
  const data = await fetch('https://...', { next: { revalidate: 3600 } })
}
export default async function Page() {
  const data = await fetch('https://...', { next: { revalidate: 3600 } })
}

Это приведёт к обновлению данных через указанное количество секунд.

Подробнее см. в справочнике API fetch.

unstable_cache

unstable_cache позволяет кэшировать результаты запросов к базе данных и других асинхронных функций. Чтобы использовать его, оберните unstable_cache вокруг функции. Например:

import { db } from '@/lib/db'
export async function getUserById(id: string) {
  return db
    .select()
    .from(users)
    .where(eq(users.id, id))
    .then((res) => res[0])
}
import { db } from '@/lib/db'

export async function getUserById(id) {
  return db
    .select()
    .from(users)
    .where(eq(users.id, id))
    .then((res) => res[0])
}
import { unstable_cache } from 'next/cache'
import { getUserById } from '@/app/lib/data'

export default async function Page({
  params,
}: {
  params: Promise<{ userId: string }>
}) {
  const { userId } = await params

  const getCachedUser = unstable_cache(
    async () => {
      return getUserById(userId)
    },
    [userId] // добавляем ID пользователя в ключ кэша
  )
}
import { unstable_cache } from 'next/cache';
import { getUserById } from '@/app/lib/data';

export default async function Page({ params } }) {
  const { userId } = await params

  const getCachedUser = unstable_cache(
    async () => {
      return getUserById(userId)
    },
    [userId] // добавляем ID пользователя в ключ кэша
  );
}

Функция принимает третий необязательный объект для определения способа обновления кэша. Он может содержать:

  • tags: массив тегов, используемых Next.js для обновления кэша.
  • revalidate: количество секунд, через которое кэш должен быть обновлён.
const getCachedUser = unstable_cache(
  async () => {
    return getUserById(userId)
  },
  [userId],
  {
    tags: ['user'],
    revalidate: 3600,
  }
)
const getCachedUser = unstable_cache(
  async () => {
    return getUserById(userId)
  },
  [userId],
  {
    tags: ['user'],
    revalidate: 3600,
  }
)

Подробнее см. в справочнике API unstable_cache.

revalidateTag

revalidateTag используется для обновления записей в кэше по тегу после определённого события. Чтобы использовать его с fetch, сначала пометьте функцию параметром next.tags:

export async function getUserById(id: string) {
  const data = await fetch(`https://...`, {
    next: {
      tags: ['user'],
    },
  })
}
export async function getUserById(id) {
  const data = await fetch(`https://...`, {
    next: {
      tags: ['user'],
    },
  })
}

Либо пометьте функцию unstable_cache параметром tags:

export const getUserById = unstable_cache(
  async (id: string) => {
    return db.query.users.findFirst({ where: eq(users.id, id) })
  },
  ['user'], // Необходимо, если переменные не передаются как параметры
  {
    tags: ['user'],
  }
)
export const getUserById = unstable_cache(
  async (id) => {
    return db.query.users.findFirst({ where: eq(users.id, id) })
  },
  ['user'], // Необходимо, если переменные не передаются как параметры
  {
    tags: ['user'],
  }
)

Затем вызовите revalidateTag в обработчике маршрута (Route Handler) или серверном действии (Server Action):

import { revalidateTag } from 'next/cache'

export async function updateUser(id: string) {
  // Изменяем данные
  revalidateTag('user')
}
import { revalidateTag } from 'next/cache'

export async function updateUser(id) {
  // Изменяем данные
  revalidateTag('user')
}

Один и тот же тег можно использовать в нескольких функциях, чтобы обновить их все одновременно.

Подробнее см. в справочнике API revalidateTag.

revalidatePath

revalidatePath используется для обновления маршрута после определённого события. Чтобы использовать его, вызовите его в обработчике маршрута (Route Handler) или серверном действии (Server Action):

import { revalidatePath } from 'next/cache'

export async function updateUser(id: string) {
  // Изменяем данные
  revalidatePath('/profile')
import { revalidatePath } from 'next/cache'

export async function updateUser(id) {
  // Изменяем данные
  revalidatePath('/profile')

Подробнее см. в справочнике API revalidatePath.