Динамические сегменты маршрутов

Когда точные названия сегментов маршрута заранее неизвестны и требуется создавать пути на основе динамических данных, можно использовать Динамические сегменты, которые заполняются во время запроса или предварительно рендерятся при сборке.

Соглашение

Динамический сегмент создаётся путём заключения имени папки в квадратные скобки: [folderName]. Например, блог может включать маршрут app/blog/[slug]/page.js, где [slug] — это Динамический сегмент для постов блога.

export default async function Page({
  params,
}: {
  params: Promise<{ slug: string }>
}) {
  const { slug } = await params
  return <div>Мой пост: {slug}</div>
}
export default async function Page({ params }) {
  const { slug } = await params
  return <div>Мой пост: {slug}</div>
}

Динамические сегменты передаются как свойство params в функции layout, page, route и generateMetadata.

МаршрутПример URLparams
app/blog/[slug]/page.js/blog/a{ slug: 'a' }
app/blog/[slug]/page.js/blog/b{ slug: 'b' }
app/blog/[slug]/page.js/blog/c{ slug: 'c' }

Сегменты с перехватом всех элементов

Динамические сегменты можно расширить для перехвата всех последующих элементов, добавив многоточие внутри скобок [...folderName].

Например, app/shop/[...slug]/page.js будет соответствовать /shop/clothes, а также /shop/clothes/tops, /shop/clothes/tops/t-shirts и так далее.

МаршрутПример URLparams
app/shop/[...slug]/page.js/shop/a{ slug: ['a'] }
app/shop/[...slug]/page.js/shop/a/b{ slug: ['a', 'b'] }
app/shop/[...slug]/page.js/shop/a/b/c{ slug: ['a', 'b', 'c'] }

Опциональные сегменты с перехватом

Сегменты с перехватом можно сделать опциональными, заключив параметр в двойные квадратные скобки: [[...folderName]].

Например, app/shop/[[...slug]]/page.js будет соответствовать не только /shop/clothes, /shop/clothes/tops, /shop/clothes/tops/t-shirts, но и /shop.

Разница между сегментами с перехватом и опциональными сегментами с перехватом в том, что опциональные соответствуют маршруту без параметра (/shop в примере выше).

МаршрутПример URLparams
app/shop/[[...slug]]/page.js/shop{ slug: undefined }
app/shop/[[...slug]]/page.js/shop/a{ slug: ['a'] }
app/shop/[[...slug]]/page.js/shop/a/b{ slug: ['a', 'b'] }
app/shop/[[...slug]]/page.js/shop/a/b/c{ slug: ['a', 'b', 'c'] }

TypeScript

При использовании TypeScript можно добавить типы для params в зависимости от настроенного сегмента маршрута.

МаршрутОпределение типа params
app/blog/[slug]/page.js{ slug: string }
app/shop/[...slug]/page.js{ slug: string[] }
app/shop/[[...slug]]/page.js{ slug?: string[] }
app/[categoryId]/[itemId]/page.js{ categoryId: string, itemId: string }

Поведение

  • Поскольку свойство params является промисом, для доступа к значениям необходимо использовать async/await или функцию use из React.
    • В версии 14 и ранее params было синхронным свойством. Для обеспечения обратной совместимости в Next.js 15 его по-прежнему можно использовать синхронно, но это поведение будет устаревшим в будущем.

Примеры

С generateStaticParams

Функция generateStaticParams может использоваться для статической генерации маршрутов во время сборки вместо генерации по запросу.

export async function generateStaticParams() {
  const posts = await fetch('https://.../posts').then((res) => res.json())

  return posts.map((post) => ({
    slug: post.slug,
  }))
}
export async function generateStaticParams() {
  const posts = await fetch('https://.../posts').then((res) => res.json())

  return posts.map((post) => ({
    slug: post.slug,
  }))
}

При использовании fetch внутри функции generateStaticParams запросы автоматически дедуплицируются. Это позволяет избежать повторных сетевых запросов для одних и тех же данных в Layouts, Pages и других функциях generateStaticParams, ускоряя сборку.