Layout, состояния и навигация
Вложенные layout, loading/error/not-found, Link и useRouter.
Обновлено
Что такое layout
Layout — интерфейс, общий для нескольких страниц: шапка, сайдбар, подвал. Вы пишете его один раз, а страницы рендерятся на месте children.
// app/blog/layout.tsx
export default function BlogLayout({ children }: LayoutProps<'/blog'>) {
return (
<div className="grid grid-cols-[200px_1fr]">
<BlogSidebar />
{children} {/* здесь появляется текущая страница */}
</div>
)
}Самое важное свойство: при навигации между дочерними страницами layout не перемонтируется — его состояние (поле ввода, прокрутка сайдбара) сохраняется. Меняется только children.
Layout вкладываются
/blog/privet = app/layout.tsx → app/blog/layout.tsx → app/blog/[slug]/page.tsx.
Layout и template — различия
layout.tsx |
template.tsx |
|
|---|---|---|
| При навигации между детьми | сохраняется, состояние остаётся | перемонтируется, состояние сбрасывается |
| Когда | почти всегда | анимации появления, сброс формы на каждой странице |
Состояния интерфейса как файлы
Next автоматически превращает специальные файлы в нужные React-компоненты:
| Файл | Становится | Когда появляется |
|---|---|---|
loading.tsx |
<Suspense fallback> вокруг страницы |
пока грузятся данные страницы |
error.tsx |
error boundary | ошибка, брошенная в сегменте |
not-found.tsx |
страница 404 | notFound() или несуществующий маршрут |
global-error.tsx |
error boundary для корневого layout | ошибки и в layout |
'use client' // error.tsx должен быть Client Component
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return (
<div>
<p>Что-то пошло не так.</p>
<button onClick={reset}>Попробовать снова</button>
</div>
)
}Что такое клиентская навигация
С обычным <a href> браузер заново скачивает всю страницу. С <Link> Next получает только изменённое и обновляет страницу без перезагрузки — layout остаются, переход мгновенный.
import Link from 'next/link'
<Link href="/blog/privet">Читать</Link><Link> ещё и делает prefetch: когда ссылка появляется на экране, Next начинает загружать маршрут в фоне.
Способы навигации — и когда
| Способ | Где | Когда |
|---|---|---|
<Link href> |
где угодно | по умолчанию — любая навигация по клику на ссылку |
useRouter().push('/x') |
Client Component | после действия: отправка формы, условная логика |
router.refresh() |
Client Component | перезапрашивает серверные данные текущей страницы |
redirect('/login') |
Server Component, Server Action | пользователю сюда нельзя / после мутации |
notFound() |
сервер | ресурса не существует |
useRouter берётся из next/navigation, а не из next/router (это Pages Router).
Активная ссылка в меню
'use client'
const pathname = usePathname()
const active = pathname === href || pathname.startsWith(href + '/')
<Link href={href} aria-current={active ? 'page' : undefined}>...</Link>Коротко
- Layout = общий интерфейс, сохраняется при навигации; template = перемонтируется.
loading,error,not-found= состояния интерфейса, объявленные файлами.<Link>для навигации без перезагрузки + prefetch;useRouterизnext/navigationдля навигации из кода.