Layouts и вложенность
Layout — общий каркас для группы страниц. Сохраняется между переходами, не перерисовывается.
Root layout
Обязателен. Оборачивает всё приложение.
app/layout.tsx:
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="ru">
<body>
<header>Шапка</header>
{children}
<footer>Подвал</footer>
</body>
</html>
);
}
Должен содержать <html> и <body>.
Вложенный layout
app/blog/layout.tsx:
export default function BlogLayout({ children }: { children: React.ReactNode }) {
return (
<div className="blog">
<aside>Сайдбар блога</aside>
<main>{children}</main>
</div>
);
}
Применяется ко всем страницам в app/blog/.
Вложенность
app/
├── layout.tsx ← root
├── page.tsx
└── blog/
├── layout.tsx ← blog
├── page.tsx
└── [id]/
└── page.tsx
Страница /blog/1 получит:
root layout
└── blog layout
└── page
Не перерисовывается
Layout сохраняется при переходах между страницами. Меняется только children. Это быстрее и сохраняет состояние.
template.tsx
Как layout, но пересоздаётся на каждом переходе:
// app/template.tsx
export default function Template({ children }: { children: React.ReactNode }) {
return <div>{children}</div>;
}
Используется для анимаций входа, useEffect при смене страницы.
loading.tsx
Показывается во время загрузки страницы:
// app/blog/loading.tsx
export default function Loading() {
return <p>Загрузка...</p>;
}
Автоматически оборачивает страницу в <Suspense>.
error.tsx
Ловит ошибки:
'use client';
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return (
<div>
<h2>Что-то пошло не так</h2>
<p>{error.message}</p>
<button onClick={reset}>Попробовать снова</button>
</div>
);
}
Должен быть клиентским компонентом.
not-found.tsx
// app/not-found.tsx
export default function NotFound() {
return <h1>404 — не найдено</h1>;
}
Вызывается через notFound():
import { notFound } from 'next/navigation';
const post = await getPost(id);
if (!post) notFound();
Комбинирование
app/
├── layout.tsx
├── loading.tsx
├── error.tsx
├── not-found.tsx
└── blog/
├── layout.tsx
├── loading.tsx
└── page.tsx
Каждый уровень может иметь свои.
Итоги
layout.tsx— общий каркас- Root layout обязателен
- Вложенные layouts применяются по цепочке
- Layout не перерисовывается
template.tsxпересоздаётсяloading,error,not-found— специальные файлы