Пошук уроків, статей та іншого контенту
Створите статичні сторінки та динамічні маршрути, що відповідають різним URL і параметрам.
Маршрут визначає, яку сторінку побачить користувач за певною URL-адресою.
У Next.js з App Router маршрути створюються за допомогою папок і файлів усередині директорії app:
app/
├── page.js
├── about/
│ └── page.js
└── posts/
└── page.jsКожен файл page.js відповідає за окремий маршрут:
app/page.js → /
app/about/page.js → /about
/postsЦей підхід називається file-system routing — маршрути визначаються структурою файлів.
Статичний маршрут має наперед відому URL-адресу. Для його створення потрібно додати папку з назвою маршруту та файл page.js.
Файл app/page.js відповідає за кореневий маршрут /:
export default function HomePage() {
return (
<main>
<h1>Головна сторінка</h1>
<p>Ласкаво просимо до нашого сайту.</p>
</main>
);
}Створимо файл app/about/page.js:
export default function AboutPage() {
return (
<main>
<h1>Про нас</h1>
<p>Це статична сторінка про нашу команду.</p>
</main>
);
}Тепер сторінка доступна за адресою:
/aboutСтворимо файл app/contact/page.js:
export default function ContactPage() {
return (
<main>
<h1>Контакти</h1>
<p>Напишіть нам на пошту.</p>
</main>
);
}Ця сторінка відповідає маршруту:
/contactСтруктура проєкту може виглядати так:
app/
├── page.js
├── about/
│ └── page.js
└── contact/
└── page.jsДля переходів між маршрутами в Next.js використовується компонент Link з модуля next/link.
Наприклад, головну сторінку можна змінити так:
import Link from "next/link";
export default function HomePage() {
return (
<main>
<h1>Головна сторінка</h1>
<nav>
<ul>
<li>
<Link href="/about">Про нас</Link>
</li>
<li>
<Link href="/contact">Контакти</Link>
</li>
</ul>
</nav>
</main>
);
}Link змінює сторінку без повного перезавантаження браузера та є стандартним способом навігації між маршрутами Next.js.
Іноді частина URL-адреси змінюється. Наприклад:
/posts/hello-nextjs
/posts/working-with-react
/posts/learn-javascriptУ кожній URL-адресі змінюється значення після /posts/. Створювати окрему папку для кожного допису незручно.
Для таких випадків використовуються динамічні сегменти.
Динамічний сегмент записується у квадратних дужках:
[id]
[slug]
[username]Створимо таку структуру:
app/
└── posts/
└── [slug]/
└── page.jsФайл app/posts/[slug]/page.js відповідатиме всім таким URL:
/posts/hello-nextjs
/posts/working-with-react
/posts/learn-javascriptЗначення між /posts/ і кінцем URL буде доступне через параметр slug.
export default async function PostPage({ params }) {
const { slug } = await params;
return (
<main>
<h1>Сторінка допису</h1>
<p>Ідентифікатор допису: {slug}</p>
</main>
);
}Якщо користувач відкриє:
/posts/hello-nextjsкомпонент отримає таке значення:
slug = "hello-nextjs"На сторінці буде показано:
Ідентифікатор допису: hello-nextjsparams містить значення динамічних сегментів URL. У сучасному App Router params використовується асинхронно, тому сторінка оголошується як async, а значення отримується через await.
Створимо невеликий сайт із головною сторінкою, списком дописів і сторінками окремих дописів.
app/
├── page.js
└── posts/
├── page.js
└── [slug]/
└── page.jsФайл app/page.js:
import Link from "next/link";
export default function HomePage() {
return (
<main>
<h1>Мій блог</h1>
<p>Це головна сторінка блогу.</p>
<Link href="/posts">Переглянути дописи</Link>
</main>
);
}Файл app/posts/page.js:
import Link from "next/link";
const posts = [
{
slug: "hello-nextjs",
title: "Знайомство з Next.js",
},
{
slug: "react-components",
title: "Компоненти React",
},
{
slug: "javascript-basics",
title: "Основи JavaScript",
},
];
export default function PostsPage() {
return (
<main>
<h1>Усі дописи</h1>
<ul>
{posts.map((post) => (
<li key={post.slug}>
<Link href={`/posts/${post.slug}`}>{post.title}</Link>
</li>
))}
</ul>
</main>
);
}Цей маршрут є статичним:
/postsОднак посилання всередині нього ведуть на динамічні маршрути:
/posts/hello-nextjs
/posts/react-components
/posts/javascript-basicsФайл app/posts/[slug]/page.js:
const posts = {
"hello-nextjs": {
title: "Знайомство з Next.js",
text: "Next.js — це фреймворк для створення React-застосунків.",
},
"react-components": {
title: "Компоненти React",
text: "Компоненти допомагають розділяти інтерфейс на незалежні частини.",
},
"javascript-basics": {
title: "Основи JavaScript",
text: "JavaScript використовується для створення інтерактивних вебзастосунків.",
},
};
export default async function PostPage({ params }) {
const { slug } = await params;
const post = posts[slug];
if (!post) {
return (
<main>
<h1>Допис не знайдено</h1>
<p>Перевірте адресу сторінки.</p>
</main>
);
}
return (
<main>
<h1>{post.title}</h1>
<p>{post.text}</p>
</main>
);
}Коли користувач відкриває /posts/react-components, Next.js:
знаходить папку [slug];
отримує значення slug з URL;
передає його в params;
відображає відповідний допис.
Динамічний маршрут можна підготувати заздалегідь для відомих значень за допомогою функції generateStaticParams.
У попередньому прикладі відомі три дописи. Додамо цю функцію до app/posts/[slug]/page.js:
const posts = {
"hello-nextjs": {
title: "Знайомство з Next.js",
text: "Next.js — це фреймворк для створення React-застосунків.",
},
"react-components": {
title: "Компоненти React",
text: "Компоненти допомагають розділяти інтерфейс на незалежні частини.",
},
"javascript-basics": {
title: "Основи JavaScript",
text: "JavaScript використовується для створення інтерактивних вебзастосунків.",
},
};
export function generateStaticParams() {
return Object.keys(posts).map((slug) => ({
slug,
}));
}
export default async function PostPage({ params }) {
const { slug } = await params;
const post = posts[slug];
if (!post) {
return (
<main>
<h1>Допис не знайдено</h1>
</main>
);
}
return (
<main>
<h1>{post.title}</h1>
<p>{post.text}</p>
</main>
);
}generateStaticParams повертає масив параметрів:
[
{ slug: "hello-nextjs" },
{ slug: "react-components" },
{ slug: "javascript-basics" }
]На їхній основі Next.js може підготувати сторінки для таких URL:
/posts/hello-nextjs
/posts/react-components
/posts/javascript-basicsВажливо розрізняти:
статичний маршрут — URL-адреса без змінної частини, наприклад /about;
динамічний маршрут — URL-адреса з параметром, наприклад /posts/[slug];
статично згенерований динамічний маршрут — динамічний маршрут, для якого відомі значення параметрів під час збирання застосунку.
idЗамість slug часто використовують числовий ідентифікатор:
app/products/[id]/page.jsТакий маршрут відповідатиме URL:
/products/1
/products/25
/products/100Приклад сторінки:
export default async function ProductPage({ params }) {
const { id } = await params;
return (
<main>
<h1>Товар</h1>
<p>Ідентифікатор товару: {id}</p>
</main>
);
}Для URL /products/25 значення id дорівнюватиме рядку "25".
Якщо потрібно використовувати його як число, перетворіть значення явно:
export default async function ProductPage({ params }) {
const { id } = await params;
const productId = Number(id);
return (
<main>
<h1>Товар</h1>
<p>Числовий ідентифікатор: {productId}</p>
</main>
);
}Параметри URL надходять як рядки, навіть якщо URL містить число.
Якщо динамічний параметр не відповідає жодному запису, сторінка може показати повідомлення про відсутність даних.
Для цього можна використати функцію notFound з next/navigation:
import { notFound } from "next/navigation";
const posts = {
"hello-nextjs": {
title: "Знайомство з Next.js",
},
};
export default async function PostPage({ params }) {
const { slug } = await params;
const post = posts[slug];
if (!post) {
notFound();
}
return (
<main>
<h1>{post.title}</h1>
</main>
);
}Якщо допис не знайдено, Next.js покаже сторінку 404 замість звичайного вмісту.
У цьому прикладі notFound() зупиняє виконання компонента, тому після нього не потрібно додавати return.
Для маршруту /about потрібна саме така структура:
app/about/page.jsФайл app/about.js не створить маршрут /about в App Router.
Динамічний сегмент потрібно записувати в квадратних дужках:
[slug]Неправильно:
slugПапка slug створить звичайний статичний маршрут /slug, а не динамічний маршрут.
awaitУ сучасному App Router параметри сторінки потрібно отримувати асинхронно:
export default async function Page({ params }) {
const { slug } = await params;
return <p>{slug}</p>;
}key у спискуПід час створення посилань через map кожному елементу потрібно додати унікальний key:
{posts.map((post) => (
<li key={post.slug}>
<Link href={`/posts/${post.slug}`}>{post.title}</Link>
</li>
))}Для переходів між сторінками застосунку використовуйте Link:
import Link from "next/link";
<Link href="/about">Про нас</Link>Це краще підходить для внутрішньої навігації Next.js, ніж звичайний HTML-елемент <a>.
Створіть такі маршрути:
/
/about
/products
/products/[id]Вимоги:
На / додайте посилання на всі інші сторінки.
На /about покажіть коротку інформацію про сайт.
На /products створіть список із трьох товарів.
Для кожного товару додайте посилання на /products/[id].
На динамічній сторінці покажіть отриманий параметр id.
Для невідомого товару покажіть повідомлення, що товар не знайдено.
Маршрути Next.js створюються за структурою папок у директорії app.
Файл page.js визначає сторінку маршруту.
Папка about разом із файлом page.js створює маршрут /about.
Динамічний сегмент записується у квадратних дужках, наприклад [slug].
Значення динамічного сегмента доступне через params.
Link використовується для навігації між внутрішніми сторінками.
generateStaticParams дає змогу заздалегідь підготувати сторінки для відомих параметрів.
Для невідомих динамічних значень можна використати notFound().