JavaRush /Курсы /Модуль 4: Node.js, Next.js и Angular /Основные файлы: layout.tsx, page.tsx, template.tsx — назн...

Основные файлы: layout.tsx, page.tsx, template.tsx — назначение

Модуль 4: Node.js, Next.js и Angular
7 уровень , 3 лекция
Открыта

1. Зачем нужны специальные файлы в App Router?

Если вы раньше работали с обычным React-приложением, то наверняка привыкли к тому, что структура папок — это просто структура папок, а не магия. В Next.js 15 с App Router всё по-другому: структура папок и имена файлов напрямую управляют маршрутизацией и поведением приложения. Это похоже на то, как если бы ваша файловая система была одновременно и картой сайта, и схемой рендеринга.

В каждой папке внутри app/ вы можете (а иногда и должны) создать специальные файлы:

  • page.tsx — отвечает за содержимое конкретной страницы.
  • layout.tsx — определяет общий "скелет" (например, шапка, подвал, меню) для всех вложенных страниц.
  • template.tsx — позволяет создавать новые "экземпляры" layout-а для каждой навигации (например, если нужно сбрасывать состояние).

Давайте разберём каждый из них подробно и с примерами.

2. page.tsx — сердце страницы

Что это такое?

Файл page.tsx — это точка входа для маршрута (route), то есть для отдельной страницы вашего сайта. Если в папке есть page.tsx, значит по этому пути будет доступна страница.


app/
└── about/
    └── page.tsx
Теперь страница будет доступна по адресу /about

Синтаксис


// app/about/page.tsx
export default function AboutPage() {
  return <h1>О нас</h1>;
}

Особенности

  • В каждом сегменте маршрута может быть только один page.tsx.
  • Именно этот файл отвечает за то, что будет показано пользователю на конкретной странице.
  • В отличие от классических маршрутизаторов, вам не нужно вручную настраивать роуты — Next.js сам найдёт все page.tsx и построит маршруты.

Пример с параметрами

Если вы хотите сделать динамическую страницу (например, для профиля пользователя), используйте квадратные скобки:


app/
└── user/
    └── [id]/
        └── page.tsx

Теперь страница будет доступна по адресу /user/123, /user/vasya и т.д.


// app/user/[id]/page.tsx
import { useParams } from 'next/navigation';

export default function UserPage() {
  // В Server Component параметры приходят через props, а не через useParams!
  // Но для простоты — пример с клиентским компонентом:
  const params = useParams();
  return <div>Профиль пользователя с id: {params.id}</div>;
}

3. layout.tsx — общий каркас страницы

Что это такое?

Файл layout.tsx — это не просто обёртка, а настоящий "скелет" для всех вложенных страниц и маршрутов. Всё, что вы поместите в layout, будет оборачивать все дочерние страницы и даже другие layout-ы, если они есть глубже.

Это похоже на то, как если бы вы строили многоэтажный дом: у каждого этажа свои стены, но фундамент и несущие конструкции (layout) общие для всех.

Синтаксис


// app/layout.tsx
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="ru">
      <body>
        <header>Это шапка сайта</header>
        <main>{children}</main>
        <footer>Это подвал</footer>
      </body>
    </html>
  );
}

Важно: layout-ы могут быть вложенными! Например, в app/blog/layout.tsx можно сделать отдельное меню только для блога.

Особенности

  • Layout-ы "живут" на всём уровне вложенности. Если вы переходите между страницами внутри одного layout-а, он не размонтируется (сохраняет состояние).
  • Если вы хотите, чтобы layout сбрасывался при переходе — вам нужен template.tsx (см. ниже).
  • Layout может быть серверным или клиентским компонентом. По умолчанию — серверный.

Пример вложенных layout-ов


app/
├── layout.tsx           // Корневой layout для всего приложения
├── blog/
│   ├── layout.tsx       // Layout только для блога
│   └── page.tsx         // Страница блога
└── about/
    └── page.tsx         // Страница "О нас"

В этом примере страница /blog будет обёрнута сначала в корневой layout, потом в blog-layout, а страница /about — только в корневой.

4. template.tsx — новый экземпляр layout-а при каждом переходе

Что это такое?

template.tsx — это специальный файл, который внешне очень похож на layout, но с одним важным отличием: он создаёт новый экземпляр при каждом переходе по маршруту.

Если layout — это как декорации в театре, которые не меняются между сценами, то template — как новые декорации для каждой новой сцены.

Когда использовать?

Используйте template.tsx, если:

  • Нужно, чтобы состояние сбрасывалось при каждом переходе на новую страницу.
  • Например, если у вас есть форма с локальным состоянием и вы хотите, чтобы при переходе на другую страницу эта форма сбрасывалась (layout не сбросит состояние, а template — да).

Синтаксис


// app/blog/[postId]/template.tsx
export default function BlogPostTemplate({ children }: { children: React.ReactNode }) {
  return (
    <section>
      <aside>Меню поста</aside>
      <article>{children}</article>
    </section>
  );
}

Пример отличия layout и template

Допустим, вы сделали layout с каким-то состоянием (например, счётчиком):


// app/counter/layout.tsx
'use client'
import { useState } from 'react';

export default function CounterLayout({ children }) {
  const [count, setCount] = useState(0);
  return (
    <div>
      <button onClick={() => setCount(count + 1)}>+1</button>
      <div>Текущее значение: {count}</div>
      {children}
    </div>
  );
}

Если вы переходите между разными страницами внутри /counter/, значение счётчика не сбросится (layout не размонтируется).

Если же вы реализуете это через template.tsx, то при каждом переходе значение сбросится — будет новый экземпляр компонента.

5. Полезные нюансы

Сравнительная таблица: layout.tsx vs page.tsx vs template.tsx

Файл Назначение Особенности
page.tsx
Содержимое конкретной страницы Только один на папку, формирует конечный маршрут
layout.tsx
Общий каркас для всех вложенных страниц Сохраняет состояние между переходами, может быть вложенным
template.tsx
Новый экземпляр layout-а для каждой навигации Сбрасывает состояние при каждом переходе, похож на layout по синтаксису

Как всё это работает вместе: схема

Вот небольшая схема, как Next.js строит дерево компонентов при переходе по маршруту /blog/42:


app/
├── layout.tsx
├── blog/
│   ├── layout.tsx
│   ├── [postId]/
│   │   ├── template.tsx
│   │   └── page.tsx

Порядок обёртывания:

  1. app/layout.tsx — корневой layout
  2. app/blog/layout.tsx — layout для блога
  3. app/blog/[postId]/template.tsx — template для конкретного поста
  4. app/blog/[postId]/page.tsx — содержимое страницы поста

6. Практический пример: создаём структуру мини-блога

Давайте на практике создадим структуру для мини-блога с главной страницей, списком постов и отдельной страницей поста.


app/
├── layout.tsx
├── page.tsx
├── blog/
│   ├── layout.tsx
│   ├── page.tsx
│   └── [postId]/
│       ├── template.tsx
│       └── page.tsx
  • app/layout.tsx — общий header/footer для всего сайта.
  • app/page.tsx — главная страница.
  • app/blog/layout.tsx — меню блога (например, фильтры, поиск).
  • app/blog/page.tsx — список всех постов.
  • app/blog/[postId]/template.tsx — сбрасывает состояние при открытии нового поста.
  • app/blog/[postId]/page.tsx — страница отдельного поста.

Пример кода для app/layout.tsx:


export default function RootLayout({ children }) {
  return (
    <html lang="ru">
      <body>
        <header>Блог компании</header>
        {children}
        <footer>© 2024 Все права защищены</footer>
      </body>
    </html>
  );
}

Пример кода для app/blog/layout.tsx:


export default function BlogLayout({ children }) {
  return (
    <section>
      <nav>Меню блога: <a href="/blog">Все посты</a></nav>
      <div>{children}</div>
    </section>
  );
}

Пример для app/blog/[postId]/template.tsx:


'use client'
import { useState } from 'react';

export default function BlogPostTemplate({ children }) {
  // Состояние сбрасывается при каждом переходе на новый пост!
  const [comment, setComment] = useState('');
  return (
    <div>
      <input
        value={comment}
        onChange={e => setComment(e.target.value)}
        placeholder="Оставьте комментарий"
      />
      {children}
    </div>
  );
}

8. Типичные ошибки при работе с layout.tsx, page.tsx и template.tsx

Ошибка №1: Пытаетесь сделать несколько page.tsx в одной папке.
Next.js не позволит — в каждом сегменте маршрута может быть только один файл page.tsx. Если хочется несколько страниц — делайте вложенные папки.

Ошибка №2: Не добавили проп children в layout/template.
Layout и template обязаны принимать проп children — иначе ничего не будет отображаться внутри!

Ошибка №3: Ожидаете, что состояние layout сбросится при переходе.
Layout сохраняет своё состояние между переходами по вложенным страницам. Если нужно сбрасывать — используйте template.tsx.

Ошибка №4: Используете хуки React в layout без 'use client'.
По умолчанию layout — серверный компонент. Если вы хотите использовать хуки (useState, useEffect), не забудьте добавить в начало файла строку 'use client'.

Ошибка №5: Путаете назначение файлов.
page.tsx — только страница, layout.tsx — только обёртка, template.tsx — только для сброса состояния. Не пытайтесь "запихнуть" всё в один файл.

Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ