Dev Highlights

Доки по разработке

This project is maintained by teniryte

3. Данные, ISR и revalidatePath

Модуль 14-isr в вашем проекте показывает, как Next.js сочетает:

3.1. Базовое ISR: экспорт revalidate

Принцип: если в странице/маршруте экспортировать константу revalidate, Next.js будет:

Пример:

// каждые 20 секунд HTML будет регенерироваться
export const revalidate = 20;

export default function Page() {
  return <div>ISR demo {new Date().toISOString()}</div>;
}

Что важно:

3.2. generateMetadata для ISR‑страниц

В ISR‑модуле вы также используете generateMetadata:

Пример:

export const revalidate = 20;

export async function generateMetadata() {
  return {
    title: '14-isr',
  };
}

export default function Page() {
  return <div>14-isr {new Date().toISOString()}</div>;
}

Принципы:

3.3. generateStaticParams и dynamicParams

Для динамических маршрутов (например, /14-isr/byslug/[slug]) можно:

Ключевые экспорты:

Пример с внешним API:

export const revalidate = 20;

// Если параметр отсутствует в generateStaticParams — делаем 404
export const dynamicParams = false;

export async function generateStaticParams() {
  const { users } = await fetch('https://dummyjson.com/users').then((res) =>
    res.json(),
  );

  return users.map((user: any) => ({
    slug: user.id.toString(),
  }));
}

Метаданные с параметром:

export async function generateMetadata({
  params,
}: {
  params: Promise<{ slug: string }>;
}) {
  const { slug } = await params;

  return {
    title: `14-isr ${slug}`,
  };
}

Страница:

export default async function Page({
  params,
}: {
  params: Promise<{ slug: string }>;
}) {
  const { slug } = await params;
  const user = await fetch(`https://dummyjson.com/users/${slug}`).then((res) =>
    res.json(),
  );

  return (
    <div>
      14-isr {user.firstName} {user.lastName}
    </div>
  );
}

Принципы:

3.4. Ручная ревалидация через revalidatePath

В модуле 14-isr/bypath вы показываете:

Сторона страницы:

import { RevalidateButton } from './RevalidateButton';

export const revalidate = 200_000;

export default function Page() {
  return (
    <div>
      <h1>Revalidate by path {new Date().toISOString()}</h1>
      <RevalidateButton />
    </div>
  );
}

Клиентская кнопка:

'use client';

import { revalidateAction } from './revalidate.action';

export function RevalidateButton() {
  return (
    <form action={revalidateAction}>
      <button type="submit">Revalidate</button>
    </form>
  );
}

Server action с revalidatePath:

'use server';

import { revalidatePath } from 'next/cache';

export async function revalidateAction() {
  // Можно делать дополнительные проверки, логирование, auth и т.п.
  revalidatePath('/14-isr/bypath');
}

Принципы:

3.5. Соединение ISR и server actions

Комбинация, которую вы используете в модуле с оптимистичными обновлениями (13-forms/04-optimistic-updates), хорошо демонстрирует связку:

Пример действия с revalidatePath:

'use server';

import { PrismaClient } from '@prisma/client';
import { revalidatePath } from 'next/cache';

const prisma = new PrismaClient();

export async function createMessage(formData: FormData) {
  const content = formData.get('content');
  if (!content) return;

  await prisma.message.create({
    data: { content: content as string },
  });

  revalidatePath('/messages'); // путь к странице, которая читает эти сообщения
}

Серверная страница:

import { PrismaClient } from '@prisma/client';
import { Messages } from './Messages';

const prisma = new PrismaClient();

export const revalidate = 0; // опционально: отключить кэш

export default async function MessagesPage() {
  const messages = await prisma.message.findMany();

  return <Messages messages={messages} />;
}

Принципы:

3.6. Когда использовать SSR, ISR и статику

Опираясь на ваш код и паттерны:

3.7. Практические рекомендации

Эти паттерны из ваших модулей 14-isr и 13-forms формируют крепкий фундамент для работы с данными в Next.js: от статических страниц до динамических, от кэша до ручной ревалидации.