Динамические сегменты маршрутов
Когда точные названия сегментов маршрута заранее неизвестны и требуется создавать пути на основе динамических данных, можно использовать Динамические сегменты, которые заполняются во время запроса или предварительно рендерятся при сборке.
Соглашение
Динамический сегмент создаётся путём заключения имени папки в квадратные скобки: [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
.
Маршрут | Пример URL | params |
---|---|---|
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
и так далее.
Маршрут | Пример URL | params |
---|---|---|
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
в примере выше).
Маршрут | Пример URL | params |
---|---|---|
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 его по-прежнему можно использовать синхронно, но это поведение будет устаревшим в будущем.
- В версии 14 и ранее
Примеры
С 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
, ускоряя сборку.