Next.js: гайд для новичков
Разбираемся с фреймворком, который используют в Netflix, Twitch и TikTok.
В этой статье я расскажу, что такое Next.js, как он помогает быстрее и проще создавать приложения, а также почему он идеально подходит для новичков. Я также объясню, как Next.js улучшает производительность твоего приложения и помогает сделать его более заметным в поисковиках.
⚠️ Важное предупреждение! этой статье мы будем в основном говорить про подход App Router в Next.js, так как он является рекомендуемым методом для новых проектов начиная с версии 13 и выше.
Почему? Потому что:
- Он предоставляет больше гибкости и мощные возможности, такие как Server Components и Nested Layouts.
- App Router активно развивается и является будущим маршрутизации в Next.js.
Из этой статьи вы узнаете:
Что такое Next.js
Next.js — инструменте для создания веб-сайтов и приложений, который был разработан компанией Vercel (раньше называлась Zeit) и выпущен в 2016 году как открытый проект. С тех пор Next.js стал одним из самых популярных инструментов среди разработчиков благодаря своей простоте, удобству и множеству полезных функций. Вот почему я считаю его таким отличным выбором для создания современных сайтов и приложений:
1. Простота и удобство разработки
С помощью Next.js можно быстро начать разработку, не тратя много времени на настройки. Он сам решает многие технические моменты, такие как маршрутизация, стилизация и сборка проекта. Это позволяет сосредоточиться на самом контенте и функционале, не думая о том, как настроить сервер или маршруты для страниц.
2. Серверная отрисовка (SSR) и статическая генерация (SSG)
Next.js дает возможность выбирать, как создавать страницы:
- Серверная отрисовка (SSR): чтобы страницы генерировались на сервере каждый раз, когда пользователь заходит на сайт. Это ускоряет загрузку страниц и помогает с поисковой оптимизацией.
- Статическая генерация (SSG): дает заранее создавать страницы во время сборки, чтобы они загружались быстрее. Это особенно полезно для сайтов с небольшими или нечасто меняющимися данными.
3. Маршрутизация через файловую систему
Next.js использует файловую систему для автоматической маршрутизации. Это означает, что в папке app каждая папка и файл могут становиться маршрутом (страницей) на сайте. Например, если я создам папку app/about, а внутри этой папки файл page.jsx, эта страница будет доступна по адресу /about. Такой подход упрощает организацию проекта и позволяет легко добавлять новые страницы без дополнительных настроек.
4. Оптимизация производительности "из коробки"
Next.js автоматически заботится о производительности сайта. Он минимизирует JavaScript, разделяет код и загружает только необходимые части страницы, когда это нужно. Это помогает пользователям быстро загружать страницы, даже если у них медленный интернет.
5. Полная совместимость с React
Так как Next.js построен на React, мы можем использовать все преимущества этого инструмента: компоненты, хуки и другие мощные фичи. Это значит, что мы можем создавать удобные, модульные интерфейсы, а также использовать React для работы с данными и состоянием на странице.
6. Гибкость и расширяемость
Next.js предоставляет массу полезных возможностей, которые позволяют нам создавать как простые, так и сложные приложения. Мы можем использовать API маршруты для работы с серверной логикой, интегрировать TypeScript для лучшей проверки кода и стилизовать сайт любым удобным для нас способом. Это делает Next.js гибким инструментом, который подойдёт для проектов разного масштаба.
На момент написания статьи актуальная версия Next.js — 15.0.4, которая вышла в октябре 2024 года.
Маршрутизация в Next.js
В Next.js маршрутизация основана на файловой системе. Это означает, что структура папок и файлов в проекте напрямую определяет URL-адреса на сайте. В Next.js доступно два способа маршрутизации: Pages Router и App Router.
1. Pages Router
Pages Router используется в папке pages/.
Как это работает:
- Каждый файл в папке pages/ становится страницей.
- Например, файл pages/about.js будет доступен по адресу /about.
bash
/pages ├── api // API маршруты │ ├── hello.js // URL: /api/hello │ └── users.js // URL: /api/users ├── blog │ ├── [id].js // URL: blog/:id (динамический маршрут) │ └── index.js // URL: https://mywebsite.ru/blog ├── about.js // URL: https://mywebsite.ru/about ├── contact.js // URL: https://mywebsite.ru/contact ├── index.js // URL: https://mywebsite.ru/ └── _app.js // Главный файл для общего оформления └── _document.js // Для настройки HTML-документа
Когда использовать Pages Router:
- Если вы работаете с классическим подходом маршрутизации.
- Если проект требует стабильности и не использует современные функции React.
2. App Router
App Router работает с папкой app/ и стал доступен начиная с Next.js 13. Это современный подход, который позволяет использовать новые функции, такие как серверные компоненты, Layouts и Partial Prerendering (PPR). Рекомендуется использовать его
Как это работает:
- Каждая папка и файл в app/ становятся маршрутом.
- Например, папка app/about с файлом page.js будет доступна по адресу /about.
bash
/app ├── about │ └── page.js // URL: https://mywebsite.ru/about ├── blog │ ├── [id] │ │ └── page.js // URL: https://mywebsite.ru/blog/:id ├── layout.js // Общий Layout для всех страниц └── page.js // URL: https://mywebsite.ru/
Когда использовать App Router:
- Если вы хотите использовать серверные компоненты и другие современные функции.
- Если работаете над новым проектом.
Server Components (Серверные компоненты)
Серверные компоненты в Next.js позволяют выполнять рендеринг на сервере и отправлять готовый HTML на клиент, минимизируя размер JavaScript, который загружается в браузер. Они особенно полезны для улучшения производительности и SEO.
Как настроить и использовать Server Components
- Использование App Router Серверные компоненты доступны только с маршрутизацией через папку app. Убедитесь, что вы используете App Router.
- Создание серверных компонентов Файлы серверных компонентов по умолчанию рендерятся на сервере. Просто используйте расширение .jsx или .tsx.
- Пример структуры файлов:
bash
/app ├── page.jsx // Главная страница (Серверный компонент) ├── layout.jsx // Общий Layout (Серверный компонент) ├── components │ ├── ServerComponent.jsx // Пример серверного компонента │ └── ClientComponent.jsx // Пример клиентского компонента
- Создание серверного компонента: Серверные компоненты можно экспортировать как обычные функции. Они могут использовать серверные API и не включают JavaScript на клиенте.
javascript
// app/components/ServerComponent.jsx export default async function ServerComponent() { const data = await fetch("https://api.example.com/data").then((res) => res.json() ); return ( <div> <h1>Данные с сервера:</h1> <pre>{JSON.stringify(data, null, 2)}</pre> </div> ); }
- Создание клиентского компонента: Если компонент должен работать с интерактивностью (например, с состояниями через React useState), используйте директиву "use client":
javascript
// app/components/ClientComponent.jsx "use client"; import { useState } from "react"; export default function ClientComponent() { const [count, setCount] = useState(0); return ( <div> <h1>Счетчик:</h1> <button onClick={() => setCount(count + 1)}>Увеличить</button> <p>Текущее значение: {count} </div> ); }
- Использование серверных и клиентских компонентов вместе: Вы можете использовать серверные компоненты как "обёртку" для клиентских:
javascript
// app/page.jsx import ServerComponent from "./components/ServerComponent"; import ClientComponent from "./components/ClientComponent"; export default function Page() { return ( <div> <ServerComponent /> <ClientComponent /> </div> ); }
- Асинхронные серверные компоненты: Серверные компоненты могут быть асинхронными, что позволяет использовать fetch и другие серверные API без необходимости дополнительного клиента:
javascript
// app/page.jsx export default async function Page() { const res = await fetch("https://api.example.com/data"); const data = await res.json(); return ( <div> <h1>Асинхронный серверный компонент</h1> <pre>{JSON.stringify(data, null, 2)}</pre> </div> ); }
Если вы попробуете использовать async function в компоненте с "use client", React на вас обидится и скажет: "Эй, я тут на клиенте, зачем мне серверные дела?".
Вот что нужно помнить:
- Компоненты с "use client" работают только в браузере, а браузер не умеет ждать асинхронные функции в рендере. Это как пытаться сделать кофе в чайнике — результат может быть, но явно не тот, что вы ожидали.
Пример ошибки:
javascript
"use client"; export default async function Oops() { // Браузер посмотрит на это и скажет: "Нет, дружище". return <div>Привет, мир!</div>; } }
Что делать?
Если вам срочно нужно что-то "асинхронное", сделайте это заранее. Например, используйте эффект (useEffect) для асинхронной логики:
javascript
"use client"; import { useEffect, useState } from "react"; export default function NoOops() { const [data, setData] = useState(null); useEffect(() => { async function fetchData() { const response = await fetch("/api/data"); const json = await response.json(); setData(json); } fetchData(); }, []); return <div>{data ? JSON.stringify(data) : "Загрузка..."}</div>; }
Динамические маршруты в Next js
Динамические маршруты позволяют создавать страницы с динамически изменяемыми частями пути, основываясь на параметрах URL. Это помогает генерировать страницы на основе данных или переменных, например, для отображения информации о различных продуктах или блогах.
В Next.js динамические маршруты создаются с помощью файлов, которые содержат параметры в квадратных скобках, например:
bash
/app └── /blog └── [slug] └── page.jsx
page.jsx – файл, который будет обрабатывать запросы с любыми значениями slug в URL. Например, если вы перейдете по адресу http://localhost:3000/blog/landing, то Next.js отобразит страницу из этого файла и передаст значение slug в компонент.
Внутри этого файла можно будет получать параметр slug из URL
javascript
export default async function BlogPost({ params }) { const {slug} = await params; return <h1>Статья: {slug}</h1>; }
Пример URL: /blog/hello-world → отображается "Статья: hello-world".
Работа с params
- params доступен для получения переменных из маршрута.
- Используйте generateStaticParams для предзагрузки данных.
Как подключить стили в Next js
В Next.js есть несколько способов добавления стилей в наше приложение. Вот основные методы, которые можно использовать для стилизации компонентов:
1. CSS Модули
CSS модули — это один из самых популярных способов стилизации в Next.js. Они позволяют создавать локальные стили для компонентов, что предотвращает конфликты имен классов.
Как использовать CSS Модули:
- Создайте файл стилей с расширением .module.css (например, styles.module.css).
- Импортируйте и используйте классы из этого файла в компонентах.
Пример:
- Создайте файл стилей styles.module.css:
css
/* styles.module.css */ .container { padding: 20px; background-color: #f0f0f0; border-radius: 8px; } .title { font-size: 2rem; color: #333; }
Импортируйте стили в компонент:
javascript
import styles from './styles.module.css'; export default function Home() { return ( <div className={styles.container}> <h1 className={styles.title}>Hello, Next.js!</h1> </div> ); }
Примечания:
- Классы в CSS модулях автоматически становятся уникальными, чтобы избежать конфликтов.
- Для использования CSS-модулей файлы должны иметь суффикс .module.css.
2. Глобальные стили
Если вам нужно добавить глобальные стили, например, для всего приложения, их можно добавить через файл globals.css.
Как использовать глобальные стили:
- Создайте файл /globals.css.
- Импортируйте его в layout.js для применения ко всем страницам.
Пример:
Создайте файл styles/globals.css:
css
body { font-family: Arial, sans-serif; margin: 0; padding: 0; background-color: #fff; } .container { max-width: 1350px; padding: 0 10px; margin: 0 auto; } h1, h2, h3 { margin: 0; padding: 0; }
Импортируйте файл globals.css в app.js:
javascript
import './globals.css'; export default function RootLayout({ children }) { return ( <html lang="ru"> <body>{children}</body> </html> ); }
Теперь эти стили будут применяться ко всем страницам вашего приложения.
Навигация перехода между страницами в Next js
Next.js предоставляет компонент Link, который является основным инструментом для перехода между страницами в приложении. Он обрабатывает оптимизацию маршрутов, кэширование, а также предотвращает полную перезагрузку страницы, что позволяет улучшить производительность.
javascript
import Link from 'next/link'; export default function Home() { return ( <nav> <Link href="/about">О нас</Link> <Link href="/blog">Блог</Link> </nav> ); }
⚠️ Важное предупреждение! Используйте компонент Link для навигации между страницами в Next.js, а не обычный тег a, потому что:
- Это предотвращает полную перезагрузку страницы, улучшая производительность.
- Он предзагружает страницы, делая переходы быстрее.
- Он оптимизирован для работы с серверной отрисовкой (SSR), что помогает в SEO.
Использование Link — это лучший и рекомендованный способ навигации в Next.js!
Получение данных в Next.js
Next.js предлагает несколько методов для получения данных, которые зависят от потребностей проекта:
1. Загрузка данных в серверных компонентах
Серверные компоненты позволяют загружать данные напрямую с сервера, используя fetch.
javascript
export default async function Page() { const res = await fetch('https://api.example.com/data', { cache: 'no-store' }); const data = await res.json(); return <div>{JSON.stringify(data)}</div>; }
-
Здесь происходит асинхронный HTTP-запрос с использованием функции fetch. Он отправляет запрос на URL https://localhost:3000/api, для получения данных.
-
Параметр { cache: 'no-store' } указывает, что браузер не должен кэшировать этот запрос. Каждый раз при рендере компонента будет выполняться новый запрос, и данные будут получены заново.
2. SSR (Server-Side Rendering)
Загрузка данных на сервере при каждом запросе через getServerSideProps.
javascript
export async function getServerSideProps() { const res = await fetch('https://api.example.com/data'); const data = await res.json(); return { props: { data } }; }
Это функция, которая выполняется на сервере при каждом запросе к странице. Она позволяет загружать данные до рендеринга страницы, и эти данные передаются как свойства (props) в компонент страницы.
3. SSG (Static Site Generation)
Статическая генерация данных во время сборки с поддержкой ISR (Incremental Static Regeneration).
javascript
export async function getStaticProps() { const res = await fetch('https://api.example.com/data',{ cache: 'force-cache' }); const data = await res.json(); return { props: { data }, revalidate: 60 }; // Обновление каждые 60 секунд }
- return { props: { data }, revalidate: 60 } — возвращает данные как пропсы для страницы. Также указано свойство revalidate: 60, что означает, что данные будут обновляться (перегенерироваться) каждые 60 секунд, даже если страница использует статическую генерацию. Это подходит для страниц, где данные могут часто изменяться.
- В данном примере используется кэширование ответа с помощью опции { cache: 'force-cache' }, чтобы минимизировать количество запросов к серверу и уменьшить нагрузку. Убедитесь, что данные кэшируются должным образом, чтобы избежать чрезмерной нагрузки на сервер.
Такой подход позволяет эффективно работать с данными, которые обновляются через определённые интервалы, без необходимости постоянно выполнять запросы.
⚠️ Важное предупреждение! По умолчанию Next.js не кэширует данные, полученные с помощью fetch. Это значит, что каждый запрос к API может привести к новой генерации страницы и дополнительной нагрузке на сервер.
4. Загрузка данных в клиентских компонентах
Для интерактивных компонентов данные можно загружать через useEffect.
javascript
'use client'; import { useEffect, useState } from 'react'; export default function Page() { const [data, setData] = useState(null); useEffect(() => { fetch('https://api.example.com/data') .then((res) => res.json()) .then(setData); }, []); return <div>{JSON.stringify(data)}</div>; }
Обработка ошибок в Next js
В Next.js страницы обрабатываются автоматически, если файл находится в соответствующей директории app. Для страницы с ошибкой 404 нужно создать файл not-found.jsx в папке app вашего проекта.
javascript
export default function NotFound() { return <h1>Страница не найдена</h1>; }
C использованием App Router, нужно создать файл not-found.jsx в директории app. Вот как должна выглядеть структура папок и файлов для этого:
bash
itvmeste/ │ ├── app/ │ ├── not-found.jsx │ ├── layout.jsx │ ├── page.jsx │ ├── some-folder/ │ │ ├── page.jsx │ │ └── other-files.js │ └── api/ │ └── route.js │ ├── public/ │ ├── images/ │ │ └── example.jpg │ └── favicon.ico │ ├── styles/ │ ├── globals.css │ └── other-styles.css │ ├── next.config.js ├── package.json └── README.md
Оптимизация изображение
Компонент Image в Next.js предоставляет оптимизированный способ работы с изображениями. Он помогает улучшить производительность приложения, автоматизируя задачи, такие как адаптация размеров, lazy loading и форматирование.
Особенности компонента Image
- Оптимизация изображений:
- Изображения автоматически ресайзятся в зависимости от устройства по
- Поддерживаются современные форматы (например, WebP).
- Lazy Loading по умолчанию:
- Изображения загружаются только тогда, когда становятся видимыми в viewport.
- Responsive и фиксированные размеры:
- Вы можете указать как фиксированные размеры изображения, так и настроить его адаптацию под разные экраны.
- CDN и кэширование:
- Next.js автоматически использует встроенный Image Optimization API, позволяя хранить обработанные изображения в кэше.
javascript
import Image from 'next/image'; export default function Home() { return ( <Image src="/images/example.jpg" // путь к изображению alt="Пример изображения" // описание для SEO width={800} // ширина обязательно height={600} // высота обязательно /> ); }
Загрузка изображений с внешнего ресурса
Если вы используете изображения, которые хранятся на стороннем сервере, нужно добавить их домен в файл next.config.js:
javascript
module.exports = { images: { remotePatterns: [ { protocol: 'https', hostname: 'example.com', // ваш домен pathname: '/images/**', // путь к изображениям }, ], }, };
Погнали, Next.js: создаём первый проект
Для того чтобы начать работу с Next.js, давайте сначала установим его.
- Убедитесь, что у вас установлен пакетный менеджер NPM или Yarn.
- Откройте терминал и перейдите в папку, в которой будет находиться проект. Для этого можно использовать команду cd
- Запустите команду ниже, которая установит последнюю версию Next.js и инициализирует новый проект.
javascript
npx create-next-app@latest
- Во время инициализации надо ответить на несколько вопросов, которые помогут настроить проект:
- Во время инициализации надо ответить на несколько вопросов, которые помогут настроить проект:
Вопрос | Перевод | Значение по умолчанию |
---|---|---|
1 What is your project named? | Имя проекта | my-app |
2 Would you like to use TypeScript? No/Yes | Вы хотите использовать TypeScript? | Yes |
3 Would you like to use ESLint? No/Yes | Вы хотите использовать ESLint? | Yes |
4 Would you like to use Tailwind CSS? No/Yes | Вы хотите использовать Tailwind CSS? | No |
5 Would you like to use src/ directory? No/Yes | Вы хотите использовать папку src? | Yes |
6 Would you like to use App Router? (recommended) | Хотели бы вы использовать App Router? (рекомендуется) | Yes |
7 Would you like to customize the import alias No/Yes | Хотите ли вы настроить псевдоним для импорта | Yes |
- Теперь вы можете запустить проект всего одной командой:
javascript
npm run dev
Поздравляем, ваш первый проект на Next.js готов и запущен!
Из чего состоит проект Next.js
Давайте посмотрим на структуру вашего проекта. Внутри проекта вы найдете несколько папок, каждая из которых имеет свою роль:
- app — страницы приложения с навигацией через app
- public — папка для хранения статических ресурсов;
- src — дополнительная папка для исходников проекта.
bash
itvmeste/ │ ├── app/ # Главная папка для всех маршрутов и компонентов │ ├── page.jsx # Главная страница (главный маршрут) │ ├── layout.jsx # Общий макет для всего приложения │ ├── error.jsx # Глобальный обработчик ошибок │ ├── not-found.jsx # Страница 404 (обработчик отсутствующих маршрутов) │ ├── api/ # Папка для маршрутов API │ │ ├── hello/ # Пример маршрута API │ │ │ └── route.js # Файл с логикой маршрута API │ ├── about/ # Пример дочернего маршрута │ │ └── page.jsx # Страница для маршрута "/about" │ └── [dynamic]/ # Пример динамического маршрута │ └── page.jsx # Динамическая страница с параметром │ ├── public/ # Папка для статических файлов (картинки, шрифты, иконки и т.д.) │ ├── images/ # Пример папки с изображениями │ └── favicon.ico # Фавиконка сайта │ ├── styles/ # Папка для стилей │ ├── globals.css # Глобальные стили │ └── other-styles.css # Дополнительные стили │ ├── next.config.js # Конфигурация Next.js ├── package.json # Файл зависимостей и скриптов └── README.md # Документация проекта
Как добавлять страницы в проект
В Next.js страницы создаются автоматически, если добавить файл в специальную папку app.
Пример создания простого шаблона:
javascript
// app/layout.jsx общий макет import Header from './Header'; import Footer from './Footer'; export default async function RootLayout({ children }) { return ( <> <Header /> <main>{children}</main> <Footer /> </> ); }
Подводим итоги
Подводя итоги, хочу отметить, что статья пытается дать общее представление о Next.js и его возможностях, но, возможно, не охватывает все нюансы и тонкости работы с этим фреймворком.
- Основное внимание уделено современному подходу App Router, который является рекомендованным для новых проектов начиная с версии 13.
- Рассмотрены важные аспекты, такие как серверные компоненты, динамические маршруты, стилизация и оптимизация производительности.
- Однако для более глубокого понимания и работы с Next.js, стоит ознакомиться с дополнительными источниками и документацией. Или задайте вопрос chat gpt она вам поможет.
Статья может быть полезной для новичков, но она не является исчерпывающей и не охватывает все детали, которые могут встретиться в реальных проектах. Все же, надеюсь, что удалось передать основные идеи и помочь разобраться с основами Next.js.