Страницы и макеты
Рекомендуем прочитать разделы Основы маршрутизации и Определение маршрутов перед продолжением.
Специальные файлы layout.js, page.js и template.js позволяют создавать пользовательский интерфейс для маршрута. Это руководство объяснит, как и когда использовать эти специальные файлы.
Страницы
Страница — это пользовательский интерфейс, уникальный для маршрута. Вы можете определить страницу, экспортировав компонент по умолчанию из файла page.js
.
Например, чтобы создать index
страницу, добавьте файл page.js
в директорию app
:

// `app/page.tsx` — это UI для URL `/`
export default function Page() {
return <h1>Привет, Домашняя страница!</h1>
}
// `app/page.js` — это UI для URL `/`
export default function Page() {
return <h1>Привет, Домашняя страница!</h1>
}
Чтобы создать дополнительные страницы, создайте новую папку и добавьте в неё файл page.js
. Например, для маршрута /dashboard
создайте папку dashboard
и добавьте в неё файл page.js
:
// `app/dashboard/page.tsx` — это UI для URL `/dashboard`
export default function Page() {
return <h1>Привет, Страница Дашборда!</h1>
}
// `app/dashboard/page.js` — это UI для URL `/dashboard`
export default function Page() {
return <h1>Привет, Страница Дашборда!</h1>
}
Полезно знать:
- Для страниц можно использовать расширения
.js
,.jsx
или.tsx
.- Страница всегда является листом (leaf) в поддереве маршрутов (route subtree).
- Файл
page.js
обязателен для публичного доступа к сегменту маршрута.- По умолчанию страницы являются Серверными Компонентами (Server Components), но могут быть настроены как Клиентские Компоненты (Client Components).
- Страницы могут получать данные. Подробнее см. в разделе Получение данных (Data Fetching).
Макеты
Макет — это пользовательский интерфейс, общий для нескольких маршрутов. При навигации макеты сохраняют состояние, остаются интерактивными и не перерендериваются. Макеты также могут быть вложенными.
Вы можете определить макет, экспортировав компонент React по умолчанию из файла layout.js
. Компонент должен принимать проп children
, который будет заполнен дочерним макетом (если он существует) или страницей во время рендеринга.
Например, макет будет общим для страниц /dashboard
и /dashboard/settings
:

export default function DashboardLayout({
children, // будет страницей или вложенным макетом
}: {
children: React.ReactNode
}) {
return (
<section>
{/* Здесь можно добавить общий UI, например, шапку или боковую панель */}
<nav></nav>
{children}
</section>
)
}
export default function DashboardLayout({
children, // будет страницей или вложенным макетом
}) {
return (
<section>
{/* Здесь можно добавить общий UI, например, шапку или боковую панель */}
<nav></nav>
{children}
</section>
)
}
Корневой макет (обязательный)
Корневой макет определяется на верхнем уровне директории app
и применяется ко всем маршрутам. Этот макет обязателен и должен содержать теги html
и body
, что позволяет изменять исходный HTML, возвращаемый сервером.
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>
{/* UI макета */}
<main>{children}</main>
</body>
</html>
)
}
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
{/* UI макета */}
<main>{children}</main>
</body>
</html>
)
}
Вложенные макеты
По умолчанию макеты в иерархии папок вложены, то есть они оборачивают дочерние макеты через проп children
. Вы можете вкладывать макеты, добавляя layout.js
в определённые сегменты маршрутов (папки).
Например, чтобы создать макет для маршрута /dashboard
, добавьте новый файл layout.js
в папку dashboard
:

export default function DashboardLayout({
children,
}: {
children: React.ReactNode
}) {
return <section>{children}</section>
}
export default function DashboardLayout({ children }) {
return <section>{children}</section>
}
Если объединить два макета выше, корневой макет (app/layout.js
) будет оборачивать макет дашборда (app/dashboard/layout.js
), который, в свою очередь, будет оборачивать сегменты маршрутов внутри app/dashboard/*
.
Два макета будут вложены следующим образом:

Полезно знать:
- Для макетов можно использовать расширения
.js
,.jsx
или.tsx
.- Только корневой макет может содержать теги
<html>
и<body>
.- Если файлы
layout.js
иpage.js
определены в одной папке, макет будет оборачивать страницу.- По умолчанию макеты являются Серверными Компонентами (Server Components), но могут быть настроены как Клиентские Компоненты (Client Components).
- Макеты могут получать данные. Подробнее см. в разделе Получение данных (Data Fetching).
- Передача данных между родительским макетом и его дочерними элементами невозможна. Однако вы можете получать одни и те же данные в маршруте несколько раз, и React автоматически дедуплицирует запросы без ущерба для производительности.
- Макеты не имеют доступа к сегментам маршрутов ниже себя. Для доступа ко всем сегментам маршрута вы можете использовать
useSelectedLayoutSegment
илиuseSelectedLayoutSegments
в Клиентском Компоненте.- Вы можете использовать Группы маршрутов (Route Groups) для включения или исключения определённых сегментов маршрутов из общих макетов.
- Вы можете использовать Группы маршрутов (Route Groups) для создания нескольких корневых макетов. См. пример здесь.
- Миграция из директории
pages
: Корневой макет заменяет файлы_app.js
и_document.js
. См. руководство по миграции.
Шаблоны
Шаблоны похожи на макеты тем, что они оборачивают каждый дочерний макет или страницу. В отличие от макетов, которые сохраняются между маршрутами и поддерживают состояние, шаблоны создают новый экземпляр для каждого из своих дочерних элементов при навигации. Это означает, что при переходе между маршрутами, использующими один шаблон, монтируется новый экземпляр компонента, пересоздаются DOM-элементы, состояние не сохраняется, и эффекты синхронизируются заново.
В некоторых случаях такое поведение может быть полезно, и шаблоны окажутся более подходящим выбором, чем макеты. Например:
- Функции, зависящие от
useEffect
(например, логирование просмотров страниц) иuseState
(например, форма обратной связи для каждой страницы). - Для изменения поведения фреймворка по умолчанию. Например, границы Suspense внутри макетов показывают fallback только при первой загрузке макета, а не при переключении страниц. Для шаблонов fallback показывается при каждой навигации.
Шаблон можно определить, экспортировав компонент React по умолчанию из файла template.js
. Компонент должен принимать проп children
.

export default function Template({ children }: { children: React.ReactNode }) {
return <div>{children}</div>
}
export default function Template({ children }) {
return <div>{children}</div>
}
С точки зрения вложенности, template.js
рендерится между макетом и его дочерними элементами. Вот упрощённый вывод:
<Layout>
{/* Обратите внимание, что шаблону присваивается уникальный ключ. */}
<Template key={routeParam}>{children}</Template>
</Layout>
Метаданные
В директории app
вы можете изменять HTML-элементы <head>
, такие как title
и meta
, используя API Метаданных.
Метаданные можно определить, экспортировав объект metadata
или функцию generateMetadata
в файле layout.js
или page.js
.
import { Metadata } from 'next'
export const metadata: Metadata = {
title: 'Next.js',
}
export default function Page() {
return '...'
}
export const metadata = {
title: 'Next.js',
}
export default function Page() {
return '...'
}
Полезно знать: Не следует вручную добавлять теги
<head>
, такие как<title>
и<meta>
, в корневые макеты. Вместо этого используйте API Метаданных, который автоматически обрабатывает сложные требования, такие как потоковая передача и дедупликация элементов<head>
.
Подробнее о доступных опциях метаданных см. в справочнике API