State Management

SWR

Документация Next.js на vercel.com грузится мгновенно, потому что страницы показывают кэш сразу, а свежесть досверяют в фоне. За этим стоит SWR - библиотека от той же Vercel, и её название это и есть стратегия: stale-while-revalidate. Отдай устаревшее, перепроверь следом. SWR делает примерно то же, что TanStack Query, но меньшим набором понятий: один хук useSWR, ключ и функция-фетчер. Выбор между двумя инструментами это не вопрос моды, а баланс объёма и потребностей проекта.

  • Сама Vercel и документация Next.js: страницы и дашборды на useSWR, отзывчивость за счёт мгновенного кэша
  • Next.js-проекты, где SWR идёт почти как штатный выбор от того же вендора
  • Лёгкие интерфейсы и виджеты: дашборд, профиль, счётчики, где хватает чтения с фоновой сверкой
  • Команды, которым нужен минимум API и вес поменьше, без мутаций-движка и devtools уровня Query
  • GitHub по докладам инженеров применяет stale-while-revalidate как принцип - тот же, что вынесен в имя SWR

Предварительные знания

  • Разделение серверного и клиентского состояния и идея кэша с TTL
  • Стратегия stale-while-revalidate: показать кэш, сверить в фоне
  • Загрузка данных через fetch и промисы
  • Server-state против client-state

Откуда взялось название stale-while-revalidate

Термин stale-while-revalidate пришёл не из фронтенда, а из HTTP: директива Cache-Control с таким именем описана в RFC 5861 (2010). Смысл прокси и браузерного кэша - отдать клиенту устаревший ответ немедленно, а свежий подтянуть в фоне. В 2019 году Vercel (тогда ZEIT) выпустила библиотеку SWR, перенеся ровно эту стратегию в React-хук для работы с данными. Имя библиотеки буквально и есть имя HTTP-директивы. Идея оказалась настолько удачной, что её под разными названиями переняли все основные инструменты серверного состояния.

Модель stale-while-revalidate в SWR

SWR сводит работу с серверными данными к одному хуку useSWR. Ему дают ключ (обычно URL) и функцию-фетчер, которая по этому ключу вернёт промис. Дальше SWR следует стратегии из своего имени: если по ключу есть кэш, он отдаётся немедленно, даже устаревший, а в фоне запускается сверка с сервером. Пришёл свежий ответ - кэш и интерфейс обновляются. Пользователь почти никогда не видит пустого спиннера, если данные уже были загружены раньше.

Ключ в SWR играет ту же роль, что queryKey в Query: он идентифицирует кэш и дедуплицирует запросы. Два компонента с ключом '/api/profile' дают один сетевой запрос и общий кэш. Фоновая сверка по умолчанию запускается при возврате фокуса на вкладку и при переподключении сети - те же триггеры, что у других инструментов, выросших из той же идеи.

  1. useSWR('/api/profile', fetcher) - кэша нет, идёт первая загрузка, isLoading равен true
  2. Данные пришли и закэшированы по ключу '/api/profile'
  3. Повторный заход на экран: кэш отдаётся мгновенно, в фоне идёт сверка
  4. Свежий ответ отличается - кэш и все подписчики ключа обновляются

Имя библиотеки это и есть её главное обещание. stale (устаревшее) показывается, while (в то время как) revalidate (идёт сверка). Поэтому интерфейс ощущается мгновенным: данные на экране есть всегда, когда они хоть раз были загружены, а корректность догоняет фоном.

Что означает стратегия stale-while-revalidate, вынесенная в имя SWR?

SWR против TanStack Query

Оба инструмента решают одну задачу - ведут серверное состояние как кэш со свежестью - и оба выросли из идеи stale-while-revalidate. Разница в объёме и философии. SWR намеренно минималистичен: ядро сосредоточено на чтении, API маленький, вес небольшой. TanStack Query шире: развитый движок мутаций с оптимистичными обновлениями, бесконечные и зависимые запросы, persist-слой и собственные devtools - всё в комплекте.

СвойствоSWRTanStack Query
ВендорVercelTanStack (Таннер Линсли)
ФокусЧтение, минимализмЧтение и запись, полный набор
МутацииБазовые, через mutateРазвитый useMutation с колбэками
Инфинит и пагинацияuseSWRInfiniteuseInfiniteQuery из коробки
DevtoolsСкромныеПолноценные devtools
ФреймворкиReact, есть портыReact, Vue, Solid, Svelte, Angular

Философски SWR ближе к 'хук для чтения данных с правильным кэшем', а Query - к 'фреймворк для всего серверного состояния'. Это не делает один лучше другого: меньший API SWR быстрее освоить и легче по весу, а более полный Query закрывает сложные сценарии без сторонних дополнений. Выбор зависит от того, насколько богаты потребности проекта по работе с данными.

  • SWR ближе по духу — Минимальный API, малый вес, фокус на чтении. Хорош, когда основное это получать и показывать данные с фоновой сверкой, а мутации простые.
  • TanStack Query ближе по духу — Полный набор: оптимистичные мутации, инфинит, зависимые запросы, devtools. Хорош, когда работа с данными сложная и нужен один инструмент на всё.

Обе библиотеки используют стратегию stale-while-revalidate, поэтому базовое чтение выглядит почти одинаково: ключ плюс фетчер. Различия проступают на сложных сценариях - мутации с откатом, бесконечная прокрутка, отладка кэша.

В чём ключевое различие между SWR и TanStack Query?

Когда какой инструмент уместнее

Выбор сводится к богатству потребностей по данным. Если проект в основном читает и показывает - дашборд, профиль, документация, виджеты - и мутации простые, SWR закрывает задачу меньшим API и весом. Особенно естественно он ложится в Next.js, потому что обе вещи от Vercel и хорошо подогнаны друг к другу. Если же в проекте много изменений данных с оптимистичными обновлениями, бесконечные ленты, зависимые цепочки запросов и нужна отладка кэша - полнота TanStack Query экономит время.

СценарийУместнееПочему
Дашборд и документация в Next.jsSWRЧтение с фоновой сверкой, тот же вендор, малый вес
Виджеты и счётчики, простые мутацииSWRМинимальный API закрывает потребность
Много оптимистичных мутаций с откатомTanStack QueryРазвитый useMutation с колбэками из коробки
Бесконечные ленты и зависимые запросыTanStack QueryuseInfiniteQuery и enabled встроены
Нужна серьёзная отладка кэшаTanStack QueryПолноценные devtools в комплекте

Важно, что неправильного выбора между ними почти нет: оба ведут серверный кэш корректно. Вопрос в том, не упрётся ли проект в потолок SWR на сложных сценариях и стоит ли тащить больший вес Query там, где хватает чтения. Решает не мода, а профиль нагрузки на данные.

Для какого проекта SWR подходит лучше, чем более полный TanStack Query?

Связь с другими темами

Урок про лёгкую альтернативу. Дальше тема раскрывается так:

  • Server-state против client-state — SWR ведёт серверное состояние как кэш - то самое разделение, что вынесено в опорный урок
  • TanStack Query: основы — Прямой конкурент с тем же назначением, но большим набором возможностей

Итог

  • SWR это библиотека Vercel для серверного состояния, и её имя - это стратегия stale-while-revalidate: показать устаревший кэш сразу, сверить с сервером в фоне
  • Стратегия пришла из HTTP-директивы Cache-Control (RFC 5861), а SWR перенесла её в хук useSWR с ключом и функцией-фетчером
  • По сравнению с TanStack Query: SWR меньше и проще, ядро сосредоточено на чтении. У Query шире встроенный движок мутаций, инфинит-запросов и devtools
  • SWR уместен в лёгких интерфейсах, особенно в Next.js от того же вендора, где хватает чтения с фоновой сверкой
  • TanStack Query уместен, когда нужны развитые мутации, оптимистичные обновления, бесконечные и зависимые запросы и инструменты отладки из коробки

Связанные уроки

  • sm-30-server-vs-client-state — SWR ведёт серверное состояние как кэш, поэтому базовое разделение server-state и client-state нужно заранее
  • sm-31-tanstack-query — TanStack Query решает ту же задачу серверного кэша, и сравнение двух инструментов помогает выбрать
SWR

0

1

Войти