Начало работы с Next.js

От автора: Next.js — это фреймворк React, который обязательно упростит вашу жизнь как разработчика. С его помощью можно абстрагировать общие и избыточные задачи (например, маршрутизацию) в относительно более простые и мощные API. Таким образом, вы можете сосредоточиться на написании приложений вместо того, чтобы изобретать колесо.

В последнее время Next.js позиционируется, как React Framework for Production, и с таким смелым заявлением он предлагает множество функций, которые помогут вам вывести ваши веб-сайты на React с нуля до готового состояния. Эти возможности имели бы меньшее значение, если бы Next.js был относительно сложен в освоении благодаря многочисленным функциям, которые подразумевают больше вещей и нюансов для изучения. Но его преимущество в простоте, мощности и большом инструментарии, это определенно является тем, что вам нужно иметь в своем арсенале.

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

Это руководство будет полезно разработчикам, которые хотят начать работу с Next.js или уже начали, но которым необходимо заполнить некоторые пробелы в знаниях. Вам не нужно быть профессионалом в React, однако опыт работы с React пригодится.

Почему именно Next.js?

1. Относительно прост в изучении.

Вот и все. Если вы хоть раз писали React, вы бы почувствовали себя как дома с Next.js. Он предлагает вам расширенные инструменты и надежную поддержку API, но не заставляет вас их использовать.

2. Встроенная поддержка CSS.

Написание CSS в компонентно-ориентированных фреймворках сопряжено с священной потребностью в «каскаде». Вот почему у вас есть инструменты CSS-in-JS, но Next.js выходит со своим собственным предложением — styled-jsx, а также поддерживает множество методологий стилизации.

3. Автоматическая поддержка TypeScript.

Если вам нравится писать код на TypeScript, с Next.js у вас буквально есть автоматическая поддержка конфигурации и компиляции TypeScript.

4. Техника множественной выборки данных.

Он поддерживает SSG и/или SSR. Вы можете использовать один или другой, или оба.

5. Маршрутизация файловой системы.

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

Есть еще много других функций, например, использование экспериментальных функций ES, таких как необязательная последовательность, отсутствие импорта React везде, где вы используете JSX, поддержка API типа next/head, он помогает управлять заголовками HTML-документа и так далее. Достаточно сказать, что чем глубже вы погружаетесь, тем больше вы наслаждаетесь, цените и открываете для себя многие другие функции.

Требования для создания приложения Next.Js.

Для создания приложения Next.js требуется установка Node.js. и утилиты для запуска npm или npx. Чтобы проверить, установлен ли у вас Node.js, запустите команду в своем терминале:

# It should respond with a version number
node -v

В идеале npm (и npx) поставляется вместе с установкой Node.js. Чтобы убедиться, что они установлены, выполните команды в терминале:

# Run this. It should respond with a version number
npm -v # Then run this. It should also respond with a version number
npx -v

Если ни одна из вышеперечисленных команд не отвечает с номером версии, вы можете изучить порядок установки Node.js и npm. Если вы предпочитаете менеджер пакетов yarn, вы можете запустить его с помощью команды:

# Installs yarn globally
npm i -g yarn

Затем подтвердите установку с помощью:

# It should also respond with a version number
yarn -v

Создание приложения Next.Js

Выполнив указанные выше требования, создать Next.js можно двумя способами, первый из них более простой: c помощью create-next-app или вручную.

Создание приложения Next.js c помощью Create-next-app.

Использовать create-next-app просто и понятно, к тому же вы также можете использовать стартер, например Next.js с Redux, Next.js с Tailwind CSS или Next.js с Sanity CMS и т. д. Вы можете просмотреть их полный список в примерах Next.js repo.

# Create a new Next.js app with npx
npx create-next-app <app-name> # Create a new Next.js app with npm
npm create-next-app <app-name> # With yarn
yarn create next-app <app-name>

Создание проекта Next.js вручную.

Для этого требуется три пакета: next, react и react-dom.

# With npm
npm install next react react-dom # With yarn
yarn add next react react-dom

Затем добавьте следующие скрипты в package.json:

"scripts": { "dev": "next dev", "start": "next start", "build": "next build"
}

dev запускает Next.js в режиме разработки.

start запускает Next.js в рабочем режиме.

build создает ваше приложение Next.js для производства.

Структура папок

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

Единственными конкретными папками Next.js являются папки pages, public и styles.

# other files and folders, .gitignore, package.json...
- pages - api - hello.js - _app.js - index.js
- public - favicon.ico - vercel.svg
- styles - globals.css - Home.module.css

Страницы

В приложении Next.js страницы — это специфические папки для Next. Вам необходимо знать некоторые вещи о страницах. Страницы — это компоненты React. Каждый файл в нем — это страница, а каждая страница — это компонент React.

// Location: /pages/homepage.js
// <HomePage/> is just a basic React component
export default HomePage() { return <h1>Welcome to Next.js</h1>
}

Пользовательские страницы — это специальные страницы с префиксом подчеркивания, например _app.js.

_app.js: Это пользовательский компонент, который находится в папке страниц. Next.js использует этот компонент для инициализации страниц.

_document.js: типа _app.js, _document.js — это специальный компонент, который Next.js использует для расширения тегов html и body ваших приложений. Это необходимо, потому что страницы Next.js пропускают определённую разметку среды документа.

Файловая система маршрутизации на основе страниц.

Next.js имеет файловую систему маршрутизации, где каждая страница автоматически становится маршрутом в зависимости от имени файла. Например, страница по адресу pages/profile будет расположена по адресу /profile, а pages/index.js по адресу /.

# Other folders
- pages - index.js # located at / - profile.js # located at /profile - dashboard - index.js # located at /dashboard - payments.js # located at /dashboard/payments

Маршрутизация

Next.js имеет файловую систему маршрутизации на основе страниц. Каждая созданная страница автоматически становится маршрутом. Например, pages/books.js станет маршрутом /book.

- pages - index.js # url: / - books.js # url: /books - profile.js # url: /profile

Маршрутизация привела к созданию таких библиотек, как React Router. Она может быть пугающей и довольно сложной из-за огромного количества способов, которые вы можете посчитать подходящими для маршрутизации раздела страниц в приложении Next.js. Говорить о маршрутизации в Next.js довольно просто. По большей части, файловая система маршрутизации может использоваться для определения наиболее распространенных шаблонов маршрутизации.

Индексные маршруты

В папке pages автоматически создается страница index.js которая перенаправляется в начальную точку вашего приложения /. У вас могут быть разные index.js страницы, но по одной в каждой папке. Вам не обязательно это делать, но это помогает определить начальную точку ваших маршрутов и избежать некоторой избыточности в именах. Возьмем, к примеру, эту структуру папок:

- pages - index.js - users - index.js - [user].js

Есть два индексных маршрута / и /users. В папке users можно назвать индексный маршрут users.js. Тогда его путь будет /users/users, если это удобно для чтения. В противном случае вы можете использовать индексный маршрут.

Вложенные каталоги

Чтобы структурировать папку, и иметь такой маршрут, как /dashboard/user/:id, вам нужны вложенные папки:

- pages - index.js - dashboard - index.js - user - [id].js # dynamic id for each user

Вы можете создавать много каталогов и углубляться сколько угодно.

Сегменты динамического маршрута

Сегменты URL-адреса не всегда определенны. Иногда просто невозможно сказать, что будет в процессе разработки. Именно здесь на помощь приходят сегменты динамического маршрута. В последнем примере :id является динамическим сегментом в URL-адресе /dashboard/user/:id. id определяет пользователя, который будет находиться на странице в данный момент. Если вы можете подумать об этом, скорее всего, вы сможете создать его с помощью файловой системы.
Динамическая часть может появляться в любом месте вложенных маршрутов:

- pages - dashboard - user - [id].js - profile

Данный пример предоставляет путь /dashboard/user/:id/profile, который ведет к странице профиля пользователя с определенным идентификатором.

Представьте, как получить доступ к маршруту /news/:category/:category-type/:league/:team, где category, category-type, league и team являются динамическими сегментами. Каждый сегмент будет файлом, и файлы не могут быть вложенными. Здесь вам понадобятся универсальные маршруты, в которых вы распределяете динамические части, например:

- pages - news - [...id].js

Тогда вы можете получить доступ к маршруту, например /news/sport/football/epl/liverpool. Вам может быть интересно, как получить динамические сегменты в компонентах. Для этой цели предназначен анкор useRouter, экспортируемый из next/router. Он открывает объект router.

import { useRouter } from 'next/router'; export default function Post() { // useRouter returns the router object const router = useRouter(); console.log({ router }); return <div> News </div>;
}

Динамические сегменты находятся в свойстве query объекта router, доступ к которому осуществляется с помощью router.query. Если запросов нет, свойство запроса возвращает пустой объект.

Ссылки между страницами

Перемещение между страницами в приложениях может выполняться с помощью компонента Link, экспортированного с помощью next/link. Скажем, у вас есть страницы:

- pages - index.js - profile.js - settings.js - users - index.js - [user].js

Вы можете использовать Link:

import Link from "next/link"; export default function Users({users) { return ( <div> <Link href="/">Home</Link> <Link href="/profile">Profile</Link> <Link href="/settings"> <a> Settings </a> </Link> <Link href="/users"> <a> Settings </a> </Link> <Link href="/users/bob"> <a> Settings </a> </Link> </div> )
}

Компонент Link имеет ряд допустимых свойств, href — URL-адрес гиперссылки — является единственным необходимым. Он эквивалентен атрибуту href элемента HTML anchor (<a>). Другие свойства включают:

Свойство: as. Значение по умолчанию: такое же как href. Описание: указывает, что отображать в адресной строке браузера.

Свойство: passHref. Значение по умолчанию: false. Описание: заставляет компонет Link передать свойство href своему дочернему элементу.

Свойство: prefetch. Значение по умолчанию: true. Описание: позволяет Next.js заблаговременно получать страницы, которые в настоящее время находятся в области просмотра, даже до их посещения, для более быстрого перехода между ними.

Свойство: replace. Значение по умолчанию: false. Описание: заменяет текущую историю переходов вместо того, чтобы помещать новый URL-адрес в стек истории.

Свойство: scroll. Значение по умолчанию: true. Описание: после перехода новая страница должна быть прокручена вверх.

Свойство: shallow. Значение по умолчанию: false. Описание: обновляет путь текущей страницы без повторного запуска getStaticProps, getServerSideProps или getInitialProps, позволяет странице иметь устаревшие данные, если они включены.

Стили

Next.js поставляется с тремя стандартными методами стилизации, глобальным CSS, модулями CSS и styled-jsx.

Линтинг и форматирование

Линтинг и форматирование, я подозреваю, это очень сложная тема, но эмпирические данные показывают, что большинство людей, которые нуждаются в этом в JavaScript, кажется, наслаждаются компанией ESLint и Prettier. Если последний идеально форматирует, то первый выравнивает вашу кодовую базу. Я привык к ESLint и Prettier Setup Уэса Боса, потому что он расширяет eslint-config-airbnb, интерполирует более красивое форматирование через ESLint, включает разумные значения по умолчанию, которые в основном подходят (для меня) и может быть отключен, если возникнет необходимость.

Включить его в проект Next.js довольно просто. Вы можете установить его глобально, если хотите, но мы будем делать это локально. Выполните приведенную ниже команду в терминале.

# This will install all peer dependencies required for the package to work
npx install-peerdeps --dev eslint-config-wesbos

Создайте файл .eslintrc в корневом каталоге приложения Next.js, наряду с папками pages, styles и public с содержимым:

{ "extends": [ "wesbos" ]
}

На этом этапе вы можете либо выполнить линтинг и форматирование кода вручную, либо позволить редактору взять на себя управление. Для линтинга и форматирования вручную требуется добавить два скрипта npm — lint и lint:fix.

"scripts": { "dev": "next dev", "build": "next build", "start": "next start" "lint": "eslint .", # Lints and show you errors and warnings alone "lint:fix": "eslint . --fix" # Lints and fixes
},

Если вы используете VSCode и предпочитаете, чтобы ваш редактор автоматически проверял и форматировал код, вам необходимо сначала установить плагин ESLint VSCode, а затем добавить следующие команды в настройки VSCode:

# Other setting
"editor.formatOnSave": true,
"[javascript]": { "editor.formatOnSave": false
},
"[javascriptreact]": { "editor.formatOnSave": false
},
"eslint.alwaysShowStatus": true,
"editor.codeActionsOnSave": { "source.fixAll": true
},
"prettier.disableLanguages": ["javascript", "javascriptreact"],

Со временем вам, скорее всего, потребуется переопределить некоторую конфигурацию, например, мне пришлось отключить правило response/jsx-props-no-spreading, которое выводит ошибки, когда свойства JSX распространяются, как в случае pageProps, пользовательского компонента страницы _app.js.

function MyApp({ Component, pageProps }) { return <Component {...pageProps} />;
}

Отключение правила происходит следующим образом:

{ "extends": [ "wesbos" ], "rules": { "react/jsx-props-no-spreading": 0 }
}

Статические файлы

На некоторых или нескольких этапах жизненного цикла вашего приложения Next.js вам понадобятся какие-либо файлы. Это могут быть иконки, собственные шрифты, изображения и т.д. В Next.js это называется Обслуживание статических файлов и есть единственный источник для них – папка public. Документация Next.js предупреждают: не называйте каталог public иначе. Его имя нельзя изменять, и это единственный каталог, используемый для обслуживания статических ресурсов.

Доступ к статическим файлам прост. Возьмем, к примеру, структуру папок ниже.

- pages profile.js
- public - favicon.ico #url /favicon.ico - assets - fonts - font-x.woff2 - font-x.woff # url: /assets/fonts/font-x.woff2 - images - profile-img.png # url: /assets/images/profile-img.png
- styles - globals.css

Вы можете получить доступ к изображению profile-img.png из компонента <Profile/>:

// <Profile/> is a React component
export default function Profile() { return { <div className="profile-img__wrap"> <img src="/assets/images/profile-img.png" alt="a big goofy grin" /> </div> }
}

или к шрифтам в папке fonts из CSS:

/* styles/globals.css */
@font-face { font-family: 'font-x'; src: url(/assets/fonts/font-x.woff2) format('woff2'), url(/assets/fonts/font-x.woff) format('woff');
}

Получение данных

Получение данных в Next.js — это огромная тема, требующая определенного уровня подготовки. Здесь мы обсудим суть. Прежде чем мы погрузимся в подробности, необходимо сначала понять, как Next.js отображает страницы.
Предварительный рендеринг — важная часть того, как работает Next.js, а также то, что делает его быстрым. По умолчанию Next.js выполняет предварительный рендеринг каждой страницы, заранее генерируя HTML- код каждой страницы вместе с минимальным кодом JavaScript, который необходимо запустить, с помощью процесса, известного как Hydration.

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

При этом существует две формы предварительного рендеринга: 1) Статическая генерация (SG), 2) Отрисовка на сервере (SSR).

Разница между ними заключается в извлечении данных. Для SG данные извлекаются во время сборки и повторно используются при каждом запросе (что делает его быстрее, поскольку его можно кэшировать), тогда как в SSR данные выбираются при каждом запросе.

Что у них общее, так это то, что их можно совмещать с рендерингом на стороне клиента с помощью fetch, Axios, SWR, React Query и т.д.

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

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

Три специальные функции:

getStaticProps — используется в SG, когда содержимое страницы зависит от внешних данных.

getStaticPaths — используется в SG, когда пути к страницам зависят от внешних данных.

getServerSideProps — используется в рендеринге на стороне сервера.

getStaticProps

getStaticProps является родственным getStaticPaths и используется в Static Generation. Это асинхронная функция, с помощью которой вы можете извлекать внешние данные и возвращать их в качестве поддержки для компонента по умолчанию на странице. Данные возвращаются как объект props и неявно сопоставляются со свойством компонента экспорта по умолчанию на странице.

В приведенном ниже примере нам нужно сопоставить учетные записи и отобразить их. Содержимое страницы зависит от внешних данных, которые мы извлекаем и применяем getStaticProps.

// accounts get passed as a prop to <AccountsPage/> from getStaticProps()
// Much more like <AccountsPage {...{accounts}} />
export default function AccountsPage({accounts}) { return ( <div> <h1>Bank Accounts</h1> {accounts.map((account) => ( <div key={account.id}> <p>{account.Description}</p> </div> ))} </div> )
} export async function getStaticProps() { // This is a real endpoint const res = await fetch('https://sampleapis.com/fakebank/api/Accounts'); const accounts = await res.json(); return { props: { accounts: accounts.slice(0, 10), }, };
}

Как видите, getStaticProps работает со статической генерацией и возвращает объект props, отсюда и название.

getStaticPaths

Подобно getStaticProps, getStaticPaths используется в статической генерации, но отличается тем, что это пути к страницам, которые являются динамическими, а не содержимым страницы. Это часто используется с getStaticProps, потому что он не возвращает никаких данных самому компоненту, вместо этого он возвращает пути, которые должны быть предварительно отрисованы во время сборки. Зная пути, вы можете продолжить получение соответствующего содержимого страницы.

Подумайте о предварительном рендеринге страницы Next.js в аспекте динамической страницы в отношении статической генерации. Чтобы он мог это сделать успешно во время сборки, он должен знать, каковы пути к страницам. Но это невозможно, потому что они динамичны и неопределенны, вот тут-то и нужно getStaticPaths.

Представьте, у вас есть приложение Next.js со страницами States и state, которые отображают список штатов в Соединенных Штатах и все государство соответственно. У вас может быть структура папок, которая выглядит так:

- pages - index.js - states - index.js # url: /states - [id].js # url /states/[id].js

Вы создаете, [id].js чтобы показать одно состояние на основе их id. Таким образом, содержимое страницы (возвращаемые данные getStaticProps) будет зависеть от путей к страницам (возвращаемых данных getStaticPaths). Сначала создадим компоненты <States/>.

// The states will be passed as a prop from getStaticProps
export default function States({states}) { // We'll render the states here
} export async function getStaticProps() { // This is a real endpoint. const res = await fetch(`https://sampleapis.com/the-states/api/the-states`); const states = await res.json(); // We return states as a prop to <States/> return { props: { states } };
}

Теперь давайте создадим динамическую страницу для одного состояния. Это причина, по которой у нас есть [id].js, чтобы мы могли сопоставить путь /states/1, или /states/2 где 1 и 2 — это id в [id].js.

// We start by expecting a state prop from getStaticProps
export default function State({ state }) { // We'll render the states here
} // getStaticProps has a params prop that will expose the name given to the
// dynamic path, in this case, `id` that can be used to fetch each state by id.
export async function getStaticProps({ params }) { const res = await fetch( `https://sampleapis.com/the-states/api/the-states?id=${params.id}` ); const state = await res.json(); return { props: { state: state[0] } };
}

Если вы попытаетесь запустить код как есть, вы получите сообщение: Error: getStaticPaths is required for dynamic SSG pages and is missing for /states/[id].

// The state component
// getStaticProps function
// getStaticPaths
export async function getStaticPaths() { // Fetch the list of states const res = await fetch("https://sampleapis.com/the-states/api/the-states"); const states = await res.json(); // Create a path from their ids: `/states/1`, `/states/2` ... const paths = states.map((state) => `/states/${state.id}`); // Return paths, fallback is necessary, false means unrecognize paths will // render a 404 page return { paths, fallback: false };
}

С помощью paths возвращенного от getStaticPaths, getStaticProps будет известно и его params параметры будут заполнены необходимыми значениями, как и id в этом случае.

Дополнения

Абсолютный импорт

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

import FormField from "../../../../../../components/general/forms/formfield"

вместо этого вы можете сделать это абсолютно так:

import FormField from "components/general/forms/formfield";

Чтобы это работало, вам понадобится файл jsconfig.json или tsconfig.json для JavaScript и TypeScript соответственно со следующим содержимым:

{ "compilerOptions": { "baseUrl": "." }
}

Это предполагает, что папка components существует в корне вашего приложения вместе с pages, styles и public.

Экспериментальные функции ES

В приложении Next.js можно использовать некоторые экспериментальные функции, такие как Оператор нулевого объединения (??) и Оператор опциональной цепочки (?.).

export default function User({user) { return <h1>{person?.name?.first ?? 'No name'}</h1>
}

Заключение

По словам команды Next.js, многие из целей, которые они поставили перед собой, были перечислены в «7 принципах создания полнофункциональных веб-приложений», и по мере того, как вы продвигаетесь в экосистеме и вглубь ее, вы поймете, что вы в надежных руках, как и многие другие пользователи, которые решили использовать Next.js для работы своих веб-сайтов / веб-приложений. Попробуйте, и после этого примите решение.

Автор: Adebiyi Adedotun

Источник: www.smashingmagazine.com

Редакция: Команда webformyself.