Как создавать макеты и страницы

Next.js использует маршрутизацию на основе файловой системы, что означает, что вы можете использовать папки и файлы для определения маршрутов. На этой странице вы узнаете, как создавать макеты и страницы, а также связывать их между собой.

Создание страницы

Страница — это пользовательский интерфейс, который отображается по определенному маршруту. Чтобы создать страницу, добавьте page файл в директорию app и экспортируйте по умолчанию React-компонент. Например, чтобы создать главную страницу (/):

page.js специальный файл
export default function Page() {
  return <h1>Hello Next.js!</h1>
}
export default function Page() {
  return <h1>Hello Next.js!</h1>
}

Создание макета

Макет — это пользовательский интерфейс, общий для нескольких страниц. При навигации макеты сохраняют состояние, остаются интерактивными и не перерисовываются.

Вы можете определить макет, экспортировав по умолчанию React-компонент из layout файла. Компонент должен принимать проп children, который может быть страницей или другим макетом.

Например, чтобы создать макет, который принимает вашу главную страницу в качестве дочернего элемента, добавьте файл layout в директорию app:

layout.js специальный файл
export default function DashboardLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body>
        {/* UI макета */}
        {/* Разместите children там, где хотите отобразить страницу или вложенный макет */}
        <main>{children}</main>
      </body>
    </html>
  )
}
export default function DashboardLayout({ children }) {
  return (
    <html lang="en">
      <body>
        {/* UI макета */}
        {/* Разместите children там, где хотите отобразить страницу или вложенный макет */}
        <main>{children}</main>
      </body>
    </html>
  )
}

Макет выше называется корневым макетом, так как он определен в корне директории app. Корневой макет обязателен и должен содержать теги html и body.

Создание вложенного маршрута

Вложенный маршрут — это маршрут, состоящий из нескольких сегментов URL. Например, маршрут /blog/[slug] состоит из трех сегментов:

  • / (Корневой сегмент)
  • blog (Сегмент)
  • [slug] (Конечный сегмент)

В Next.js:

  • Папки используются для определения сегментов маршрута, которые соответствуют сегментам URL.
  • Файлы (такие как page и layout) используются для создания UI, который отображается для сегмента.

Чтобы создать вложенные маршруты, вы можете вкладывать папки друг в друга. Например, чтобы добавить маршрут для /blog, создайте папку с именем blog в директории app. Затем, чтобы сделать /blog общедоступным, добавьте файл page.tsx:

Иерархия файлов, показывающая папку blog и файл page.js
// Фиктивные импорты
import { getPosts } from '@/lib/posts'
import { Post } from '@/ui/post'

export default async function Page() {
  const posts = await getPosts()

  return (
    <ul>
      {posts.map((post) => (
        <Post key={post.id} post={post} />
      ))}
    </ul>
  )
}
// Фиктивные импорты
import { getPosts } from '@/lib/posts'
import { Post } from '@/ui/post'

export default async function Page() {
  const posts = await getPosts()

  return (
    <ul>
      {posts.map((post) => (
        <Post key={post.id} post={post} />
      ))}
    </ul>
  )
}

Вы можете продолжать вкладывать папки для создания вложенных маршрутов. Например, чтобы создать маршрут для конкретного поста в блоге, создайте новую папку [slug] внутри blog и добавьте файл page:

Иерархия файлов, показывающая папку blog с вложенной папкой slug и файлом page.js
function generateStaticParams() {}

export default function Page() {
  return <h1>Hello, Blog Post Page!</h1>
}
function generateStaticParams() {}

export default function Page() {
  return <h1>Hello, Blog Post Page!</h1>
}

Заключение имени папки в квадратные скобки (например, [slug]) создает динамический сегмент маршрута, который используется для генерации нескольких страниц из данных. Например, посты в блоге, страницы продуктов и т. д.

Вложенные макеты

По умолчанию макеты в иерархии папок также вложены, что означает, что они оборачивают дочерние макеты через проп children. Вы можете вкладывать макеты, добавляя layout внутрь определенных сегментов маршрута (папок).

Например, чтобы создать макет для маршрута /blog, добавьте новый файл layout внутри папки blog.

Иерархия файлов, показывающая корневой макет, оборачивающий макет blog
export default function BlogLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return <section>{children}</section>
}
export default function BlogLayout({ children }) {
  return <section>{children}</section>
}

Если объединить два макета выше, корневой макет (app/layout.js) будет оборачивать макет блога (app/blog/layout.js), который, в свою очередь, будет оборачивать страницу блога (app/blog/page.js) и страницу поста (app/blog/[slug]/page.js).

Создание динамического сегмента

Динамические сегменты позволяют создавать маршруты, которые генерируются из данных. Например, вместо ручного создания маршрута для каждого отдельного поста в блоге вы можете создать динамический сегмент для генерации маршрутов на основе данных постов.

Чтобы создать динамический сегмент, заключите имя сегмента (папки) в квадратные скобки: [segmentName]. Например, в маршруте app/blog/[slug]/page.tsx [slug] является динамическим сегментом.

export default async function BlogPostPage({
  params,
}: {
  params: Promise<{ slug: string }>
}) {
  const { slug } = await params
  const post = await getPost(slug)

  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
    </div>
  )
}
export default async function BlogPostPage({ params }) {
  const { slug } = await params
  const post = await getPost(slug)

  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
    </div>
  )
}

Узнайте больше о Динамических сегментах.

Связывание страниц

Вы можете использовать компонент <Link> для навигации между маршрутами. <Link> — это встроенный компонент Next.js, который расширяет HTML-тег <a> для предоставления предварительной загрузки и навигации на стороне клиента.

Например, чтобы сгенерировать список постов в блоге, импортируйте <Link> из next/link и передайте проп href компоненту:

import Link from 'next/link'

export default async function Post({ post }) {
  const posts = await getPosts()

  return (
    <ul>
      {posts.map((post) => (
        <li key={post.slug}>
          <Link href={`/blog/${post.slug}`}>{post.title}</Link>
        </li>
      ))}
    </ul>
  )
}
import Link from 'next/link'

export default async function Post({ post }) {
  const posts = await getPosts()

  return (
    <ul>
      {posts.map((post) => (
        <li key={post.slug}>
          <Link href={`/blog/${post.slug}`}>{post.title}</Link>
        </li>
      ))}
    </ul>
  )
}

Полезно знать: <Link> — это основной способ навигации между маршрутами в Next.js. Вы также можете использовать хук useRouter для более сложной навигации.