Использование хуков SWR React с инкрементной статической регенерацией Next.js (ISR)
Опубликовано: 2022-03-10Если вы когда-либо использовали добавочную статическую регенерацию (ISR) с Next.js, вы, возможно, обнаружили, что отправляете устаревшие данные клиенту. Это происходит при повторной проверке страницы на сервере. Для некоторых веб-сайтов это работает, но для других (таких как Scrapbook Hack Club, сайт, созданный @lachlanjc, который я помогаю поддерживать) пользователь ожидает, что данные будут поддерживаться в актуальном состоянии.
Первое решение, которое приходит на ум, может состоять в том, чтобы просто отображать страницы на стороне сервера, гарантируя, что клиенту всегда будут отправляться самые последние данные. Однако извлечение больших фрагментов данных перед рендерингом может замедлить начальную загрузку страницы. Решение, использованное в Scrapbook, заключалось в использовании SWR-библиотеки хуков React для обновления кэшированной страницы с сервера с получением данных на стороне клиента . Такой подход гарантирует, что пользователи по-прежнему будут иметь хороший опыт, что сайт работает быстро и что данные поддерживаются в актуальном состоянии.
Познакомьтесь с SWR
SWR — это библиотека React Hooks, созданная Vercel, название происходит от термина stale-while-revalidate. Как следует из названия, вашему клиенту будут предоставляться устаревшие/старые данные, в то время как самые актуальные данные извлекаются (перепроверяются) через SWR на стороне клиента. SWR не просто проверяет данные один раз, однако вы можете настроить SWR для повторной проверки данных через определенный интервал времени, когда вкладка восстанавливает фокус, когда клиент повторно подключается к Интернету или программно.
В сочетании с маршрутами ISR и API Next.js SWR можно использовать для создания гибкого взаимодействия с пользователем . Сначала клиент получает кешированную статически сгенерированную страницу (сгенерированную с помощью getStaticProps()
), в фоновом режиме сервер также начинает процесс повторной проверки этой страницы (подробнее здесь). Этот процесс кажется клиенту быстрым, и теперь он может видеть набор данных, однако он может быть немного устаревшим. После загрузки страницы выполняется запрос на выборку вашего маршрута API Next.js, который возвращает те же данные, что и сгенерированные с помощью getStaticProps()
. Когда этот запрос будет выполнен (при условии, что он был успешным), SWR обновит страницу этими новыми данными.
Давайте теперь вернемся к Scrapbook и к тому, как он помог решить проблему устаревших данных на странице . Очевидно, что теперь клиент получает обновленную версию. Однако более интересным является влияние на скорость нашей стороны. Когда мы измеряем скорость через Lighthouse, мы получаем индекс скорости 1,5 секунды для варианта сайта ISR + SWR и 5,8 секунды для варианта рендеринга на стороне сервера (плюс предупреждение о начальном времени ответа сервера). Это довольно резкий контраст между ними (и это было заметно и при загрузке страниц). Но есть и компромисс: на странице «Визуализация на стороне сервера» у пользователя не было изменения макета сайта через пару секунд после поступления новых данных. Хотя я считаю, что Scrapbook хорошо справляется с этим обновлением, это важное соображение, когда дизайн вашего пользовательского опыта.
Где использовать КСВ (и где не использовать)
SWR можно разместить в самых разных местах, вот несколько категорий сайтов, где SWR отлично подойдет:
- Сайты с оперативными данными, которые требуют быстрого обновления.
Примерами таких сайтов могут быть сайты спортивных результатов и отслеживание рейсов. При создании этих сайтов рекомендуется использовать параметр повторной проверки через интервал с настройкой низкого интервала (от одной до пяти секунд). - Сайты со стилем ленты обновлений или сообщений, которые обновляются в режиме реального времени.
Классическим примером этого могут быть новостные сайты, которые ведут живые блоги о таких событиях, как выборы. Другим примером может быть вышеупомянутый альбом для вырезок. В этом случае вы также, вероятно, захотите использовать параметр повторной проверки через интервал, но с более высоким значением интервала (тридцать-шестьдесят секунд), чтобы сэкономить на использовании данных и предотвратить ненужные вызовы API. - Сайты с более пассивными обновлениями данных, которые люди часто держат открытыми в фоновом режиме.
Примерами таких сайтов могут быть страницы погоды или страницы с номерами случаев COVID-19 в 2020-х годах. Эти страницы обновляются не так часто и поэтому не нуждаются в постоянной повторной проверке, как в предыдущих двух примерах. Тем не менее, это все равно улучшит взаимодействие с пользователем для обновления данных. В этих случаях я бы рекомендовал перепроверить дату, когда вкладка восстанавливает фокус и когда клиент повторно подключается к Интернету, это будет означать, что если человек с тревогой возвращается к крану, надеясь, что произошло лишь небольшое увеличение случаев COVID, они получить эти данные быстро. - Сайты с небольшими фрагментами данных, с которыми пользователи могут взаимодействовать.
Подумайте о кнопке «Подписаться на Youtube». Когда вы нажимаете кнопку «Подписаться», вы хотите увидеть изменение счетчика и почувствовать, что вы изменили ситуацию. В этих случаях вы можете повторно проверить данные программно, используя SWR, чтобы получить новый счетчик и обновить отображаемую сумму.
Следует отметить, что все они могут применяться как с ISR, так и без него.
Конечно, есть места, где вы не захотите использовать КСВ или использовать КСВ без ISR. SWR бесполезен, если ваши данные не меняются или изменяются очень редко, и вместо этого может забивать ваши сетевые запросы и использовать данные мобильного пользователя. SWR может работать со страницами, требующими аутентификации, однако в этих случаях вы захотите использовать рендеринг на стороне сервера, а не инкрементную статическую регенерацию.
Использование SWR с Next.js и инкрементная статическая регенерация
Теперь, когда мы изучили теорию этой стратегии, давайте посмотрим, как мы применяем ее на практике. Для этого мы собираемся создать веб-сайт, который показывает, сколько такси доступно в Сингапуре (где я живу!), используя этот API, предоставленный правительством.
Структура проекта
Наш проект будет работать с тремя файлами:
-
lib/helpers.js
-
pages/index.js
(наш файл интерфейса) -
pages/api/index.js
(наш файл API)
Наш вспомогательный файл будет экспортировать функцию ( getTaxiData
), которая будет извлекать данные из внешнего API, а затем возвращать их в подходящем формате для нашего использования. Наш файл API будет импортировать эту функцию и установит ее экспорт по умолчанию в функцию-обработчик, которая вызовет функцию getTaxiData
, а затем вернет ее, это будет означать, что отправка запроса GET в /api
вернет наши данные.
Нам понадобится эта возможность, чтобы SWR выполнял выборку данных на стороне клиента. Наконец, в нашем файле внешнего интерфейса мы импортируем getTaxiData
и используем его в getStaticProps
, его данные будут переданы в функцию экспорта по умолчанию нашего файла внешнего интерфейса, которая будет отображать нашу страницу React. Мы делаем все это, чтобы предотвратить дублирование кода и обеспечить согласованность наших данных. Какой глоток, давайте приступим к программированию прямо сейчас.
Файл помощников
Мы начнем с создания функции getTaxiData
в lib/helpers.js
:
export async function getTaxiData(){ let data = await fetch("https://api.data.gov.sg/v1/transport/taxi-availability").then(r => r.json()) return {taxis: data.features.properties[0].taxi_count, updatedAt: data.features.properties[0].timestamp} }
Файл API
Затем мы создадим функцию обработчика в api/index.js
, а также импортируем функцию getTaxiData
:
import { getTaxiData } from '../../lib/helpers' export default async function handler(req, res){ res.status(200).json(await getTaxiData()) }
Здесь нет ничего уникального для SWR или ISR, кроме вышеупомянутой структуры проекта. Теперь все это начинается в index.js
!
Внешний файл
Первое, что мы хотим сделать, это создать нашу функцию getStaticProps
! Эта функция импортирует нашу функцию getTaxiData
, использует ее, а затем возвращает данные с некоторой дополнительной конфигурацией.
export async function getStaticProps(){ const { getTaxiData } = require("../lib/helpers") return { props: (await getTaxiData()), revalidate: 1 } }
Я хотел бы сосредоточиться на ключе повторной проверки в нашем возвращаемом объекте. Этот ключ практически включает добавочную статическую регенерацию. Он сообщает вашему хосту, что регенерация статической страницы каждую секунду является доступной опцией, эта опция затем запускается в фоновом режиме, когда клиент посещает вашу страницу. Подробнее об инкрементной статической регенерации (ISR) можно прочитать здесь.
Пришло время использовать SWR! Давайте сначала импортируем его:
import useSWR from 'swr'
Мы собираемся использовать SWR в нашей функции рендеринга React, поэтому давайте создадим эту функцию:
export default function App(props){ }
Мы получаем реквизиты от getStaticProps
. Теперь мы готовы настроить SWR:
const fetcher = (...args) => fetch(...args).then(res => res.json()) const { data } = useSWR("/api", fetcher, {fallbackData: props, refreshInterval: 30000})
Давайте разберем это. Во-первых, мы определяем сборщика. Это требуется SWR в качестве аргумента, чтобы он знал, как получить ваши данные, учитывая, что разные фреймворки и т. д. могут иметь разные настройки. В этом случае я использую функцию, представленную на странице документов SWR. Затем мы вызываем хук useSWR
с тремя аргументами: путь для получения данных, функция получения и затем объект параметров.
В этом объекте options
мы указали две вещи:
- резервные данные;
- Интервал, с которым SWR должен перепроверять данные.
Опция резервных данных — это то, где мы предоставляем данные, полученные из getStaticProps
, что гарантирует, что данные видны с самого начала. Наконец, мы используем деструктурирование объекта для извлечения данных из хука.
Чтобы закончить, мы отобразим эти данные с помощью очень простого JSX:
return <div>As of {data.updatedAt}, there are {data.taxis} taxis available in Singapore!</div>
И мы сделали это! Там у нас есть очень простой пример использования КСВ с добавочной статической регенерацией. (Исходный код нашего примера доступен здесь.)
Если вы когда-нибудь столкнетесь с устаревшими данными с помощью ISR, вы знаете, кому звонить: SWR.
Дальнейшее чтение на SmashingMag
- Библиотека SWR React Hooks
- Введение в SWR: React Hooks для удаленной выборки данных, Ибрахима Ндав
- ISR против DPR: громкие слова, краткое объяснение, Кэссиди Уильямс
- Global vs. Local Styling In Next.js, Александр Дубовой
- Маршрутизация на стороне клиента в Next.js, Адебии Адедотун Лукман