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

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

Соглашение

Динамический сегмент создается путем заключения имени папки в квадратные скобки: [folderName]. Например, [id] или [slug].

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

Пример

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

export default function Page({ params }: { params: { slug: string } }) {
  return <div>Мой пост: {params.slug}</div>
}
export default function Page({ params }) {
  return <div>Мой пост: {params.slug}</div>
}
МаршрутПример 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' }

Подробнее о генерации параметров для сегмента см. на странице generateStaticParams().

Полезно знать: Динамические сегменты эквивалентны Динамическим маршрутам в директории pages.

Генерация статических параметров

Функция 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,
  }))
}

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

Используйте руководство по миграции, если переходите с директории pages.

Подробнее и расширенные сценарии использования см. в документации по функции generateStaticParams.

Сегменты с перехватом всех путей (Catch-all)

Динамические сегменты можно расширить для перехвата всех последующих сегментов, добавив многоточие внутри скобок [...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.

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

МаршрутПример URLparams
app/shop/[[...slug]]/page.js/shop{}
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 в зависимости от конфигурации сегмента маршрута.

export default function Page({ params }: { params: { slug: string } }) {
  return <h1>Моя страница</h1>
}
export default function Page({ params }) {
  return <h1>Моя страница</h1>
}
МаршрутТип 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 }

Полезно знать: В будущем это может автоматически выполняться плагином TypeScript.