React Junior
207 subscribers
37 photos
462 links
Изучение React с нуля
加入频道
Next.js. useSWR

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

#nextjs #серверныйрендеринг #документация
👍3🔥1
Next.js. getStaticPaths - fallback

Параметр fallback определяет поведение Next.js при обращении к странице с несуществующим динамическим параметром.

fallback: false

Если fallback: false, то для неперечисленных параметров будет возвращаться страница 404. Это удобно, если у вас не очень много роутов и они не часто добавляются.

fallback: true

Если fallback: true, то при обращении к странице с несуществующим параметром будет возвращена "резервная" версия страницы.

Резервная - значит, с пустыми пропсами. При этом у объекта роутера поле isFallback будет равно true:

import { userRouter } from 'next/router';

function Post({ post }) {
const router = useRouter();

if (router.isFallback) {
// рендеринг экрана загрузки
}

// рендеринг поста
}


Резервная страница будет отображаться до тех пор, пока Next в фоновом режиме не сгенерирует HTML и JSON для новой страницы (getStaticProps). Затем браузер получит JSON и отрендерит новую страницу, а новый путь добавится в список "уже отрендеренных". По сути у нас тут SSR.

Этот подход полезен, если у вас очень много страниц, которые зависят от данных (например, товары в интернет-магазине). Если рендерить страницы для всех товаров при сборке, это займет слишком много времение, поэтому изначально рендерим лишь некоторые страницы (getStaticPaths) и включаем fallback: true.

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

fallback: 'blocking'

Если fallback: 'blocking', то будет то же самое, что и для fallback: true, но резервная страница во время загрузки отображаться не будет.

#nextjs #серверныйрендеринг #документация
👍4
Next.js. Layouts

Статья в документации (англ.): https://nextjs.org/docs/basic-features/layouts

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

Если у нас для всех страниц один лейаут, то проще всего подключить его в файле pages/_app.js (это компонент, инициализирующий активную страницу, подробнее здесь). Просто импортируем нужный лейаут и оборачиваем им контент страницы.

Если же у разных страниц разные лейауты, нужно идти другим путем.

Проще всего указать нужный лейаут прямо в теле компонента страницы, но тут есть один нюанс. Если в лейауте есть какое-то состояние (например, поле ввода), то при смене страниц оно будет сбрасываться, даже если лейаут один и тот же.

Демо: https://codesandbox.io/p/sandbox/jolly-agnesi-w90pmj?file=%2Fpages%2Fcomponents%2FLayoutWithState.tsx&selection=%5B%7B%22endColumn%22%3A24%2C%22endLineNumber%22%3A15%2C%22startColumn%22%3A24%2C%22startLineNumber%22%3A15%7D%5D

У нас есть две страницы, которые подключают в своем теле компонент LayoutWithState. Этот компонент имеет внутреннее состояние (useState). При переключении между страницами это состояние сбрасывается.

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

Мы можем добавить нашим страницам статический метод getLayout, который будет возвращать нужную обертку. Если вы используете TypeScript, понадобится создать новый тип NextPageWithLayout, расширяющий NextPage.

Внутри компонента-инициализатора App проверяем, есть ли у текущией страницы этот метод. Если есть, то вызываем его, чтобы получить нужную разметку.

Для обеих страниц переносим рендер обертки в метод getLayout. Теперь при переключении страницы состояние в лейауте сохраняется, так как React не заменяет компонент обертки на новый экземпляр.

Демо: https://codesandbox.io/p/sandbox/next-js-layouts-react-junior-forked-vl930n?file=%2Fpages%2F_app.tsx&selection=%5B%7B%22endColumn%22%3A1%2C%22endLineNumber%22%3A21%2C%22startColumn%22%3A1%2C%22startLineNumber%22%3A21%7D%5D

#nextjs #серверныйрендеринг #примерыкода #документация
👍2🔥2
Next.js. Изображения

Статьи в документации (англ.):
- https://nextjs.org/docs/basic-features/image-optimization
- https://nextjs.org/docs/api-reference/next/image

Next.js предоставляет собственный компонент Image, который является оберткой над стандартным img. Этот компонент умеет много полезного, например, самостоятельно может определять размеры изображений, чтобы предотвратить кумулятивный сдвиг страницы (CLS), реализует ленивую загрузку, умеет отображать плейсхолдер - и это наверняка не все его достоинства.

Основные атрибуты у него стандартные: src, alt, width и height, с тонкостями разберемся далее.

#nextjs #серверныйрендеринг #документация
👍4🔥1
Next.js. Image. Источник изображения

Image может работать и с локальными, и с удаленными файлами, причем с локальными - больше плюшек.

Локальные изображения

Изображения проекта должны храниться в папке public. Импортируем их в нужный компонент и передаем в проп src компонента Image.

Для таких изображений даже необязательно указывать width и height, если они не отличаются от оригинальных. Во время сборки Next проанализирует файл изображения, определит его размеры и подставит самостоятельно.

Динамический импорт не поддерживается.

Удаленные изображения

В src можно указать и обычный урл (относительный или абсолютный). Если используются абсолютные пути, то домены обязательно нужно добавить в файл next.config.js в секцию images.remotePatterns.

module.exports = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'example.com',
},
],
},
}


#nextjs #серверныйрендеринг #документация
👍5
Next.js. Image. srcset

Компонент Image рендерит стандартный тег img и проставляет для него массу полезных атрибутов, например, srcset. Что именно в нем будет, зависит от пропа sizes (https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/sizes). Если этот проп не передан, будет всего пара размеров, но может быть и очень большой список.

srcset генерируется и для локальных, и для удаленных изображений.

Видео (англ.): https://www.youtube.com/watch?v=R4sdWUI3-mY&ab_channel=BrunoAntunes

В начале видео очень подробно и понятно рассказывается об атрибутах srcset и sizes. Вторая часть (про Next.js) немного устарела, с момента записи произошли некоторые изменения.

#nextjs #серверныйрендеринг #документация
👍3🔥1
Next.js. Image. Ленивая загрузка

Изображения, сгенерированные компонентом Image по умолчанию грузятся "лениво" - только когда попадают во вьюпорт.
Если указать проп placeholder=blur, то до окончательной загрузки будет отображаться размытая версия изображения. Для локальных изображений она сгенерируется автоматически, а для всех остальных можно указать нужный адрес в пропе blurDataURL.

#nextjs #серверныйрендеринг #документация
👍5
Next.js. Image

Еще несколько полезных пропсов:

- fill - привязывает размеры изображения к размерам родительского контейнера. Работает как position: absolute + inset: 0.

- quality - позволяет управлять качеством картинки (от 1 до 100). По умолчанию 75.

- priority - указывает, что картинку нужно загрузить как можно быстрее, без ленивой загрузки. Следует использовать для Largest Contentful Paint.

#nextjs #серверныйрендеринг #документация
👍3🔥1
Next.js. Image. Собственный лоадер и настройка srcset

Мы можем самостоятельно настроить урлы изображений, которые попадают в конечный srcset, передав свой собственный лоадер в проп loader.

Лоадер это обычная функция, которая принимает адрес (src), ширину и качество (quality). И должна вернуть урл изображения для заданной ширины. Если у вас есть апи, который умеет изменять размер и качество изображений, здесь можно его использовать. Но в целом у Next.js как будто нормальный дефолтный лоадер.

Откуда берутся значения ширины? Из настроек images.deviceSizes и image.imageSizes в файле next.config.js. По умолчанию там уже заданы большие наборы, при необходимости их можно переопределить. Оба эти массива объединяются для формирования srcset.

#nextjs #серверныйрендеринг #документация
👍2🔥1
Next.js. Image. Форматы изображений

Последняя приятная плюшка компонента Image, о которой я упомяну - это автоматическое использование производительных форматов. Если браузер клиента поддерживает webp, то изображение будет в webp, даже если вы сохранили его в jpg.

Настроить разрешенные форматы можно в next.config.js в поле images.formats.

#nextjs #серверныйрендеринг #документация
🔥3👍2
Next.js. Оптимизация шрифтов

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

Все шрифты хостятся на вашем сервере (гугловские шрифты загружаются во время сборки и тоже помещаются на сервер).

Для работы понадобится пакет @next/font.

Локальные шрифты

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

import localFont from '@next/font/local';

const myFont1 = localFont({ src: './my-font.woff2' });

const myFont2 = localFont({
src: [
{
path: './Roboto-Regular.woff2',
weight: '400',
style: 'normal',
},
{
path: './Roboto-Italic.woff2',
weight: '400',
style: 'italic',
},
]
});


Функция localFont возвращает объект с полями className и style.

Применять такой загруженный шрифт нужно с помощью сгенерированного имени класса. Для нужного элемента в разметке устанавливаем проп className={myFont.className}. Теперь для этого элемента установлено нужное значение font-family.

Google-шрифты

Для гугл-шрифтов нужно импортировать функции из пакета @next/font/google. Потребуется указать подмножество шрифта и при необходимости настройки, например, вес и стиль:

import { Inter } from '@next/font/google';
import { Roboto } from '@next/font/google';

const inter = Inter({ subsets: ['latin'] })
const roboto = Roboto({
weight: '400',
subsets: ['latin'],
});
const roboto1 = Roboto({
weight: ['400', '700'],
style: ['normal', 'italic'],
subsets: ['latin'],
});


Используем эти шрифты точно так же, через className.

Шрифты в head

Можно использовать и более привычный вариант - указать шрифты в теге style с помощью синтаксиса jsx. Это следует делать в файле _app.tsx. Значение берем из myFont.style.fontFamily. Важно сделать блок со стилями глобальным (атрибут global, чтобы стили были помещены в head.

Демо: https://codesandbox.io/p/sandbox/wizardly-dream-5gv4mx?file=%2Fpages%2Findex.tsx&selection=%5B%7B%22endColumn%22%3A37%2C%22endLineNumber%22%3A3%2C%22startColumn%22%3A37%2C%22startLineNumber%22%3A3%7D%5D

В демке для документа установлен глобальный стиль с font-family: Inter (файл pages/_app.tsx). На главной странице (pages/index.tsx) загружен шрифт Pacifico. Он установлен для одного абзаца с помощью className.

Статья в документации: https://nextjs.org/docs/basic-features/font-optimization

#nextjs #серверныйрендеринг #документация #примерыкода
🔥3👍1
TypeScript в Next.js

Соберем в одном месте типы, которые использует Next:

Данные для серверного рендеринга - GetStaticProps, GetStaticPaths, GetServerSideProps

import { GetStaticProps, GetStaticPaths, GetServerSideProps } from 'next';
export const getStaticProps: GetStaticProps = async function (context) {
// ...
}
export const getStaticPaths: GetStaticPaths = async function () {
// ...
}
export const getServerSideProps: GetServerSideProps = async function (context) {
// ...
}


API-роуты - NextApiRequest, NextApiResponse

import type { NextApiRequest, NextApiResponse } from 'next'

export default function handler(req: NextApiRequest, res: NextApiResponse) {
res.status(200).json({ name: 'John Doe' })
}


Тип NextApiResponse может также принимать обобщенный тип данных ответа.

Компонент App - AppProps

import type { AppProps } from 'next/app'

export default function MyApp({ Component, pageProps }: AppProps) {
// ...
}


#nextjs #документация #typescript
👍3🔥1
Next.js. Динамические роуты

Про динамические роуты мы уже знаем: можно создать файл pages/post/[id].tsx и он будет соответствовать множеству страниц /post/1, post/2, post/hello и т.д.

При этом в компоненте страницы можно узнать конкретный id, воспользовавшись хуком useRouter (в поле router.query.id).

Но это только один уровень вложенности, то есть страницу /post/react/23 так не опишешь. Если требуется вложенная структура, Next и это умеет.

Создаем страницу pages/post/[...id].tsx и получаем все возможные пути с любым уровнем вложенности.

При этом router.query.id будет не строкой, а массивом.

Если к этому набору урлов требуется добавить еще и просто /post (без id), название файла должно выглядеть так: pages/post/[[...id]].tsx.

#nextjs #серверныйроутинг #документация
👍3🔥1
Next.js. Api-роуты: примеры использования

Обычно не следует вызывать из апи-роута другой апи, но есть пара случаев, когда можно:

- вы хотите спрятать урл, к которому обращаетесь (поэтому запрос с клиента происходит на ваш апи /api/secret, а уже оттуда - на нужный https://company.com/secret-url)
- вы хотите использовать какие-то переменные окружения для формирования запроса

#nextjs #серверныйрендеринг #документация
👍1🔥1
Next.js. Динамические api-роуты

Для апи работают те же самые правила, что и для страниц.
Динамическую часть можно указать в квадратных скобках - api/post/[id].ts.
Если добавить три точки, будут отслеживаться все уровни вложенности - api/post/[...ids].ts.
Если при этом поставить двойные квадратные скобки, то будет опциональный вариант (будет совпадение если нет параметров вообще - api/post).
Доступ к динамическим параметрам можно получить из request.query.

#nextjs #серверныйрендеринг #документация
👍4
Next.js. Request и Response Helpers

В апи-роутах у нас приходит два параметра - объект запроса (req) и объект ответа (res).

req - это экземпляр класса http.IncomingMessage, а res - http.ServerResponse, но и тот, и другой имеют дополнительные плюшки (хелперы).

- req.cookies - все отправленные куки.
- req.query - параметры строки запроса.
- req.body - тело запроса, обработанное в соответствии с content-type.

- res.status(code) - метод для установки HTTP-кода ответа
- res.json(body) - отправить JSON
- res.send(body) - отправить HTTP-ответ (строчку, объект или Buffer)
- res.redirect([status, ], path) - для редиректа
- res.revalidate(urlPath) - ревалидация страницы по запросу.

Кроме того, из каждого роута в папке pages/api мы можем экспортировать объект конфигурации:

export const config = {
api: {

}
}


Подробнее можно посмотреть в документации:
https://nextjs.org/docs/api-routes/request-helpers
https://nextjs.org/docs/api-routes/response-helpers

#nextjs #серверныйрендеринг #документация
🔥3👍1
Next.js. Деплой проекта на Vercel

Vercel - это удобный хостинг для проектов на Next.js.

Развернуть проект очень-очень просто, даже у меня быстро получилось.
Просто регистрируемся на Vercel.com, создаем репозиторий с проектом (GitHub, GitLab, BitBucket) и импортируем его в Vercel.

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

Мой учебный проект: https://furrycat.vercel.app/

Есть еще вариант задеплоить на Netlify или Heroku (но сейчас Heroku не регистрирует пользователей из России).
Подробнее тут: https://dzen.ru/a/YmuUb-ZF519-uyRP

#nextjs #серверныйрендеринг #инструменты
👍2🔥1
Next.js. Деплой на Node-сервере

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

- next build - для сборки проекта
- next start - для запуска Next-сервера

#nextjs
👍4
Next.js. Подготовка к продакшену

Статья в документации (англ.): https://nextjs.org/docs/going-to-production

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

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

#nextjs #серверныйрендеринг #документация #отложено #оптимизация
👍4
Next.js. Аутентификация

Статья в документации (англ.): https://nextjs.org/docs/authentication

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

Итак, есть два основных подхода:

1. Открывать страничку с состоянием загрузки (неаутентифицированную), а данные пользователя получать уже на клиенте и перерендеривать страницу после получения. Такую страничку можно статически генерировать, чтобы она открывалась очень быстро и можно было размещать еее на CDN.
2. Использовать SSR, то есть получать данные пользователя на сервере и возвращать страницу с контентом для уже известного пользователя. Используем для этого getServerSideProps. В этом случае не будет "моргания неавторизованного контента", а пользовать сразу получит то, что заслуживает (готовую страницу). Но если аутентификация занимает много времени, такой подход может принести проблемы.

Дальше посмотрим на примеры и готовые решения.

#nextjs #серверныйрендеринг #документация #аутентификация
👍3