docs(pages): Переписать весь раздел.
This commit is contained in:
@@ -1,101 +1,26 @@
|
|||||||
---
|
---
|
||||||
title: Страницы (App Router)
|
title: Файлы роутинга
|
||||||
---
|
---
|
||||||
|
|
||||||
# Страницы (App Router)
|
# Файлы роутинга
|
||||||
|
|
||||||
Специальные файлы Next.js App Router, которые фреймворк использует по соглашению: `layout.tsx`, `page.tsx`, `loading.tsx`, `error.tsx`, `not-found.tsx`, `template.tsx`.
|
Правила для специальных файлов App Router (`page.tsx`, `layout.tsx`, `error.tsx`, `not-found.tsx` и др.) — чем наш подход отличается от дефолтного.
|
||||||
|
|
||||||
## Общие правила
|
## Организация
|
||||||
|
|
||||||
- Экспорт через `export default function` — конвенция Next.js.
|
- `page.tsx` — тонкий файл: только `metadata` и рендер экрана. Логика, стили и зависимости живут в экране, не в `page.tsx`.
|
||||||
- Типизация через `PropsWithChildren` или явный интерфейс.
|
- `error.tsx` и `not-found.tsx` делегируют разметку экранам по тому же принципу.
|
||||||
- Каждая страница (`page.tsx`) должна содержать `metadata` с `title` и `description`.
|
- `layout.tsx` — точка подключения провайдеров и глобальных стилей. Вёрстка layout-обёрток выносится в слой `layouts/`.
|
||||||
- Минимум логики — page-level компоненты делегируют работу экранам, виджетам и фичам.
|
- Стили в файлах роутинга не используются — стилизация только внутри вызываемых компонентов.
|
||||||
- Стили в page-level компонентах не используются — стилизация внутри вызываемых компонентов.
|
|
||||||
|
|
||||||
## layout.tsx
|
## Реализация
|
||||||
|
|
||||||
Корневой layout — точка подключения провайдеров, глобальных стилей и метаданных.
|
- Каждый `page.tsx` экспортирует `metadata` с `title` — он подставляется в шаблон корневого layout (`%s | App`).
|
||||||
|
- Корневой `layout.tsx` задаёт `metadata` с `title.template`, `description`, `metadataBase` и OpenGraph-настройками.
|
||||||
|
|
||||||
```tsx
|
## Примеры
|
||||||
import type { PropsWithChildren } from 'react'
|
|
||||||
import type { Metadata } from 'next'
|
|
||||||
import { Providers } from './providers'
|
|
||||||
import './styles/index.css'
|
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
`src/app/profile/[id]/page.tsx`
|
||||||
title: {
|
|
||||||
default: 'App',
|
|
||||||
template: '%s | App',
|
|
||||||
},
|
|
||||||
description: 'Описание приложения',
|
|
||||||
metadataBase: new URL('https://example.com'),
|
|
||||||
openGraph: {
|
|
||||||
type: 'website',
|
|
||||||
locale: 'ru_RU',
|
|
||||||
siteName: 'App',
|
|
||||||
images: [
|
|
||||||
{
|
|
||||||
url: '/og-image.png',
|
|
||||||
width: 1200,
|
|
||||||
height: 630,
|
|
||||||
alt: 'App',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
twitter: {
|
|
||||||
card: 'summary_large_image',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function RootLayout({ children }: PropsWithChildren) {
|
|
||||||
return (
|
|
||||||
<html lang="ru" suppressHydrationWarning>
|
|
||||||
<body>
|
|
||||||
<Providers>
|
|
||||||
{children}
|
|
||||||
</Providers>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Вложенный layout — для секции с общей обёрткой (sidebar, header):
|
|
||||||
|
|
||||||
```tsx
|
|
||||||
import type { PropsWithChildren } from 'react'
|
|
||||||
import { DashboardLayout } from '@/shared/ui/dashboard-layout'
|
|
||||||
|
|
||||||
export default function Layout({ children }: PropsWithChildren) {
|
|
||||||
return (
|
|
||||||
<DashboardLayout>
|
|
||||||
{children}
|
|
||||||
</DashboardLayout>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## page.tsx
|
|
||||||
|
|
||||||
Тонкий файл — только импорт и рендер экрана. Логика, стили и зависимости размещаются в экране, не в `page.tsx`.
|
|
||||||
|
|
||||||
```tsx
|
|
||||||
import type { Metadata } from 'next'
|
|
||||||
import { HomeScreen } from '@/screens/home'
|
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
|
||||||
title: 'Главная',
|
|
||||||
description: 'Главная страница приложения',
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function HomePage() {
|
|
||||||
return <HomeScreen />
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
С параметрами маршрута:
|
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
import type { Metadata } from 'next'
|
import type { Metadata } from 'next'
|
||||||
@@ -117,21 +42,7 @@ export default async function ProfilePage({ params }: ProfilePageProps) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Каждая страница должна содержать `metadata` с `title` — он подставится в шаблон из корневого layout: `Профиль | App`.
|
`src/app/error.tsx`
|
||||||
|
|
||||||
## loading.tsx
|
|
||||||
|
|
||||||
Состояние загрузки. Показывается пока загружается контент страницы.
|
|
||||||
|
|
||||||
```tsx
|
|
||||||
export default function Loading() {
|
|
||||||
return <div>Загрузка...</div>
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## error.tsx
|
|
||||||
|
|
||||||
Обработка ошибок. Обязательно `'use client'` — error boundary работает только на клиенте. Разметку выносим в экран.
|
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
'use client'
|
'use client'
|
||||||
@@ -150,33 +61,3 @@ const ErrorPage: FC<ErrorPageProps> = ({ error, reset }) => {
|
|||||||
|
|
||||||
export default ErrorPage
|
export default ErrorPage
|
||||||
```
|
```
|
||||||
|
|
||||||
## not-found.tsx
|
|
||||||
|
|
||||||
Страница 404. Показывается когда маршрут не найден. Разметку выносим в экран.
|
|
||||||
|
|
||||||
```tsx
|
|
||||||
import type { Metadata } from 'next'
|
|
||||||
import { NotFoundScreen } from '@/screens/not-found'
|
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
|
||||||
title: 'Страница не найдена',
|
|
||||||
description: 'Запрашиваемая страница не существует',
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function NotFound() {
|
|
||||||
return <NotFoundScreen />
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## template.tsx
|
|
||||||
|
|
||||||
Аналог layout, но пересоздаётся при каждой навигации (не сохраняет состояние). Используется редко — для анимаций переходов между страницами.
|
|
||||||
|
|
||||||
```tsx
|
|
||||||
import type { PropsWithChildren } from 'react'
|
|
||||||
|
|
||||||
export default function Template({ children }: PropsWithChildren) {
|
|
||||||
return <div>{children}</div>
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|||||||
Reference in New Issue
Block a user