JavaRush /Курсы /Модуль 4: Node.js, Next.js и Angular /Разница Page Router и App Router: концепции, примеры

Разница Page Router и App Router: концепции, примеры

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

1. Page Router: классика Next.js

Если вы только начали изучать Next.js, то вполне вероятно, что вы столкнулись с вопросом:
"Почему в одном проекте папка pages, а в другом — app? В чём разница? Какой способ лучше?"

Это не баг, а фича! Next.js исторически развивался с классическим Page Router (pages/). Со временем команда Next.js внедрила новый, более современный подход — App Router (app/).
Сейчас оба способа существуют параллельно, но App Router — будущее Next.js.

Концепция

Page Router — это старый-добрый способ организации маршрутов в Next.js, который появился ещё в первых версиях фреймворка.
Главная идея: каждый файл в папке pages/ становится отдельной страницей (роутом) вашего сайта.

Пример структуры:


/pages
  ├── index.js         // Главная страница: /
  ├── about.js         // Страница "О нас": /about
  └── blog
      └── [id].js      // Динамическая страница: /blog/123
  • Все файлы в папке pages/ автоматически становятся маршрутами.
  • Файл pages/index.js — это корень сайта (/).
  • Файл pages/about.js — страница /about.
  • Файл с квадратными скобками ([id].js) — динамический маршрут: /blog/123, /blog/abc и т.д.

Как работает Page Router?

  • Каждый компонент из pages/ — это React-компонент, который экспортируется по умолчанию (export default).
  • Можно использовать функции getStaticProps, getServerSideProps, getInitialProps для загрузки данных.
  • Для навигации используется компонент <Link href="/about"> и хук useRouter().

Пример кода: страница About


// pages/about.js
export default function About() {
  return <h1>О компании</h1>;
}

Особенности Page Router

  • Всё просто и прозрачно.
  • Поддерживает статическую генерацию (SSG), серверный рендеринг (SSR), инкрементальную регенерацию (ISR).
  • Хорошо подходит для небольших и средних проектов.
  • Ограниченная гибкость в организации макетов (layouts) и вложенных шаблонов.

2. App Router: современный взгляд на маршрутизацию

App Router — это новая архитектура маршрутизации, введённая в Next.js 13 и активно развиваемая в Next.js 15.
Главная идея: вся маршрутизация строится на папке app/, где каждая папка — потенциальный маршрут, а специальные файлы (page.js, layout.js, loading.js, и др.) определяют структуру и поведение страницы.

Пример структуры:


/app
  ├── page.js            // Главная страница: /
  ├── about
  │     └── page.js      // Страница "О нас": /about
  └── blog
        ├── [id]
        │    └── page.js // Динамический маршрут: /blog/123
        └── layout.js    // Макет для блога

Пояснение:

  • Каждый подкаталог в app/ — это сегмент маршрута.
  • Файл page.js (или page.tsx) — компонент страницы.
  • Файл layout.js — компонент макета (layout), оборачивает вложенные страницы.
  • Можно использовать loading.js для отображения состояния загрузки, error.js для ошибок, template.js для шаблонов и т.д.
  • Поддержка Server Components (серверные компоненты), Client Components (клиентские), Server Actions и других современных фич.

Как работает App Router?

  • Строит дерево маршрутов на основе структуры папок и файлов.
  • Позволяет создавать вложенные макеты, параллельные маршруты, группировать страницы и компоненты.
  • Поощряет разделение на Server и Client Components для оптимизации производительности.
  • Для навигации используется тот же <Link />, но есть нюансы с состоянием, асинхронной загрузкой и т.п.

Пример кода: страница About


// app/about/page.js
export default function AboutPage() {
  return <h1>О компании (App Router)</h1>;
}

3. Таблица сравнения: Page Router vs App Router

Характеристика Page Router (pages/) App Router (app/)
Где живут маршруты В папке
/pages
В папке
/app
Принцип маршрутизации Файл = страница Папка = сегмент, файл page.js = страница
Макеты (layouts) Только через
_app.js
, слабая вложенность
Любая вложенность через
layout.js
Динамические маршруты
[id].js
[id]/page.js
Загрузка данных
getStaticProps
,
getServerSideProps
Любой async Server Component
Server/Client Components Только Client Components Server и Client Components
Поддержка Server Actions Нет Да
Гибкость шаблонов Ограниченная Максимальная (layout, template, error)
Статус Поддерживается, но legacy Новый стандарт, развивается

4. Примеры: как выглядит одно и то же приложение

Пример 1. Главная страница и страница "О нас"

Page Router:


/pages
  ├── index.js    // /
  └── about.js    // /about

// pages/index.js
export default function Home() {
  return <h1>Главная</h1>;
}

// pages/about.js
export default function About() {
  return <h1>О нас</h1>;
}

App Router:


/app
  ├── page.js          // /
  └── about
        └── page.js    // /about

// app/page.js
export default function HomePage() {
  return <h1>Главная (App Router)</h1>;
}

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

Пример 2. Динамический маршрут "Пост блога"

Page Router:


/pages
  └── blog
        └── [id].js    // /blog/123

// pages/blog/[id].js
import { useRouter } from 'next/router';

export default function BlogPost() {
  const router = useRouter();
  const { id } = router.query;
  return <h1>Пост блога: {id}</h1>;
}

App Router:


/app
  └── blog
        └── [id]
              └── page.js    // /blog/123

// app/blog/[id]/page.js
export default function BlogPost({ params }) {
  return <h1>Пост блога: {params.id}</h1>;
}

Обратите внимание: В App Router параметры маршрута передаются через пропс params, а не через хук.

5. Ключевые концепции App Router

Layouts (Макеты) и вложенность

App Router позволяет создавать отдельные макеты для разных частей сайта. Например, у блога может быть свой layout, который будет оборачивать все страницы блога (и только их).


/app
  ├── layout.js           // Общий макет для всего сайта
  └── blog
        ├── layout.js     // Макет только для блога
        └── [id]
              └── page.js

// app/layout.js
export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <header>Меню сайта</header>
        <main>{children}</main>
        <footer>Подвал</footer>
      </body>
    </html>
  );
}

// app/blog/layout.js
export default function BlogLayout({ children }) {
  return (
    <section>
      <nav>Меню блога</nav>
      <div>{children}</div>
    </section>
  );
}

Страницы блога будут автоматически обёрнуты в оба макета: сначала RootLayout, потом BlogLayout.

Server и Client Components

App Router поощряет использование серверных компонентов по умолчанию (они не попадают в JS-бандл на клиент). Для интерактивности используется директива 'use client' в начале файла.


// app/counter/page.js
'use client';

import { useState } from 'react';

export default function Counter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>Счётчик: {count}</button>;
}

Асинхронная загрузка данных

В App Router можно делать асинхронные компоненты (async function), сразу загружая данные на сервере:


// app/users/page.js
export default async function UsersPage() {
  const res = await fetch('https://jsonplaceholder.typicode.com/users');
  const users = await res.json();
  return (
    <ul>
      {users.map(user => <li key={user.id}>{user.name}</li>)}
    </ul>
  );
}

6. Когда использовать Page Router, а когда App Router?

Page Router (pages/):

  • Если у вас старый проект, и вы не хотите его переписывать.
  • Если не нужны новые фичи (Server Components, layouts, Server Actions).
  • Если хочется стабильности и понятности.

App Router (app/):

  • Если вы начинаете новый проект.
  • Если нужны современные возможности Next.js.
  • Если хочется максимальной гибкости, вложенных макетов, SSR/SSG/ISR "на стероидах".
  • Если не боитесь учить новое (а это, судя по тому, что вы читаете эту лекцию, — про вас!).

Важно: В одном проекте можно использовать оба подхода, но это не рекомендуется для новых проектов.

7. Типичные ошибки и особенности перехода

Ошибка №1: Путаете синтаксис параметров.
В Page Router параметры маршрута (например, [id]) получаете через хук useRouter, а в App Router — через пропс params. Если перепутаете — получите undefined или ошибку.

Ошибка №2: Пытаетесь использовать getStaticProps/getServerSideProps в App Router.
В App Router эти функции больше не работают! Загрузка данных теперь делается через async Server Components.

Ошибка №3: Забываете про layout.js и page.js.
В App Router маршрут без файла page.js не считается страницей и не будет доступен по URL.

Ошибка №4: Не указываете 'use client' там, где нужен интерактивный код.
По умолчанию компоненты в App Router — серверные. Если используете useState, useEffect и т.п., обязательно добавьте 'use client' в начало файла.

Ошибка №5: Путаете вложенность макетов.
В App Router макеты могут быть вложенными, и порядок обёртывания важен. Не забывайте, что layout.js влияет на все вложенные сегменты.

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