react-query vs SWR
react-query vs SWR

Давайте сначала познакомимся с обоеми библиотеками, чтобы сравнить их и убедиться, что лучше. react-query и SWR — это две популярные библиотеки для управления состоянием данных в React-приложениях. Они обе предназначены для облегчения работы с данными, получаемыми с сервера, но имеют некоторые различия в функциональности и подходах.

react-query

react-query — это мощная библиотека для управления состоянием данных в React-приложениях. Она предоставляет простые и эффективные инструменты для работы с данными, получаемыми с сервера, и упрощает взаимодействие с API-запросами. Ниже познакомимся с базовыми фичами данной библиотеки:

Кеширование данных: Одна из основных возможностей react-query — это кеширование данных. При выполнении запросов к серверу библиотека автоматически кэширует полученные данные. Это позволяет избежать повторных запросов на сервер при обращении к тем же данным в разных частях приложения. Кэш react-query также автоматически инвалидируется при обновлении данных на сервере или вручную с помощью инвалидации.

// инвалидация
queryClient.invalidateQueries()

Автоматическое обновление данных: react-query предоставляет механизм автоматического обновления данных на основе определенных событий. Когда выполняется запрос на сервер, библиотека автоматически обновляет кэшированные данные при успешном завершении запроса, мутации или ручных вызовах обновления. Это позволяет всегда иметь актуальные данные в приложении.

Повторные запросы: В случае ошибок при выполнении запроса react-query предоставляет механизм повторных запросов, который автоматически попытается повторить запрос. Это особенно полезно при работе с нестабильным интернет-соединением или временными проблемами на стороне сервера. А так же можно настроить интервал между повторными запросами или указать максимальное количество повторов в настройках.

Оптимистические обновления: react-query поддерживает оптимистические обновления данных. Это позволяет обновлять кэшированные данные немедленно, еще до того, как запрос на сервер будет завершен. Это создает плавное впечатление для пользователей и повышает отзывчивость интерфейса.

Обработка ошибок и повторные запросы: Библиотека упрощает обработку ошибок при выполнении запросов. Она предоставляет механизм повторных запросов при ошибках, что позволяет автоматически попробовать повторить запрос для получения данных. Это особенно полезно при работе с нестабильным интернет-соединением или временными проблемами на стороне сервера.

Гибкая настройка запросов: Библиотека предоставляет гибкие средства для настройки запросов, позволяя контролировать кэширование, время жизни данных, политики повторных запросов и многое другое.

// установка значения по умолчанию глобально
import { QueryClient } from '@tanstack/react-query';

const queryClient = new QueryClient({
   defaultOptions: {
      queries: {
      staleTime: Infinity,
    },
  },
});

// установка значения по умолчанию для
// определенных запросов
queryClient.setQueryDefaults(
  ['todos'], { staleTime: 3000 }
)

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

Интеграция с React: react-query разработана специально для работы с React и интегрируется с ним без проблем. Она предоставляет хуки и компоненты, которые позволяют удобно взаимодействовать с данными и отображать их в интерфейсе React-компонентов.

// пример использования библиотеки в проекте
import {
  QueryClient,
  QueryClientProvider,
  useQuery,
} from '@tanstack/react-query'

const queryClient = new QueryClient()

export default function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <Example />
    </QueryClientProvider>
  )
}

function Example() {
  const { isLoading, error, data } = useQuery({
    queryKey: ['repoData'],
    queryFn: () =>
      fetch('https://api.github.com/repos/TanStack/query').then(
        (res) => res.json(),
      ),
  })

  if (isLoading) return 'Loading...'

  if (error) return 'An error has occurred: ' + error.message

  return (
    <div>
      <h1>{data.name}</h1>
      <p>{data.description}</p>
      <strong>???? {data.subscribers_count}</strong>{' '}
      <strong>✨ {data.stargazers_count}</strong>{' '}
      <strong>???? {data.forks_count}</strong>
    </div>
  )
}
// пример GET, POST запросов
import {
  useQuery,
  useMutation,
  useQueryClient,
  QueryClient,
  QueryClientProvider,
} from '@tanstack/react-query'
import { getTodos, postTodo } from '../my-api'

const queryClient = new QueryClient()

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <Todos />
    </QueryClientProvider>
  )
}

function Todos() {
  const queryClient = useQueryClient()

  const query = useQuery({ queryKey: ['todos'], queryFn: getTodos })

  // Мутации
  const mutation = useMutation({
    mutationFn: postTodo,
    onSuccess: () => {
      // Инвалидация и обновлени данных 
      queryClient.invalidateQueries({ queryKey: ['todos'] })
    },
  })

  return (
    <div>
      <ul>
        {query.data?.map((todo) => (
          <li key={todo.id}>{todo.title}</li>
        ))}
      </ul>

      <button
        onClick={() => {
          mutation.mutate({
            id: Date.now(),
            title: 'Do Laundry',
          })
        }}
      >
        Add Todo
      </button>
    </div>
  )
}

render(<App />, document.getElementById('root'))

SWR

SWR (Stale-While-Revalidate) — это библиотека для управления состоянием данных в React-приложениях, которая ориентирована на кеширование данных и автоматическую валидацию. Она предоставляет простой и эффективный способ работы с данными, получаемыми с сервера, и упрощает обновление данных в интерфейсе приложения. Ниже познакомимся с базовыми фичами данной библиотеки:

Кеширование данных: Одной из основных возможностей SWR является кеширование данных, получаемых с сервера. Когда выполняется запрос на сервер, библиотека автоматически кэширует полученные данные. Это позволяет избежать повторных запросов на сервер при обращении к тем же данным в разных частях приложения.

Автоматическая валидация данных: SWR использует стратегию “Stale-While-Revalidate”, что означает, что она возвращает старые данные из кэша (если они доступны) и одновременно запускает повторный запрос на сервер для получения актуальных данных. Таким образом, пользователь всегда видит старые данные, даже если сервер уже вернул новые. Это позволяет предоставить пользователю мгновенный отклик и актуальные данные после завершения повторного запроса.

Повторные запросы: В случае ошибок при выполнении запроса SWR предоставляет механизм повторных запросов, который автоматически попытается повторить запрос. Это особенно полезно при работе с нестабильным интернет-соединением или временными проблемами на стороне сервера.

Оптимистические обновления: SWR также поддерживает оптимистические обновления данных. Это означает, что при обновлении данных на сервере, она моментально обновляет данные в кэше и показывает пользователю обновленные данные без ожидания ответа от сервера. После успешного завершения запроса на сервер, кэш автоматически обновляется с актуальными данными.

Политики повторных запросов: SWR позволяет гибко настраивать повторные запросы с помощью различных политик. Например, вы можете установить интервал между повторными запросами или указать максимальное количество повторов.

Интеграция с React: SWR разработана для интеграции с React и предоставляет хук useSWR(), который позволяет удобно взаимодействовать с данными и обрабатывать состояние запросов.

const fetcher = (...args) => fetch(...args).then(res => res.json());

//пример использования библиотеки в проекте
import useSWR from 'swr'
 
function Profile () {
  const { data, error, isLoading } = useSWR('/api/user/123', fetcher)
 
  if (error) return <div>ошибка загрузки</div>
  if (isLoading) return <div>загрузка...</div>
 
  // рендер данных
  return <div>привет, {data.name}!</div>
}

Теперь, давайте сравнивать эти две библиотеки и определить, какой лучше выбрать:

Как мы поняли, основной упор библиотеки react-query делается на управление данными на клиентской стороне приложения, особенно на работу с данными, получаемыми с сервера (API-запросы). react-query предлагает мощные средства для кеширования данных, автоматической инвалидации кэша и обработки запросов.

SWR в первую очередь ориентирована на кеширование и автоматическую валидацию данных, получаемых с сервера. Она предоставляет удобные средства для кеширования и повторных запросов данных с поддержкой стратегии “Stale-While-Revalidate” (сохранение старых данных, пока выполняется повторный запрос).

Также react-query предоставляет гибкие средства для настройки запросов и поддерживает мутации, позволяя легко выполнять изменения данных на сервере, для этого react-query предоставляет хуки (useMutation()useQuery()) и компоненты для удобного взаимодействия с запросами и мутациями. SWR в свою очередь предоставляет только один хук — useSWR, который позволяет выполнять запросы и автоматически кэшировать данные, а также обрабатывать их обновления и ошибки.

Итог

В общем, если ваш проект огромный и имеет много GET/POST запросов, то лучше использовать react-query, если проект не большой и не имеет много запросов, то лучше выбирать SWR. Всё зависит от объем и функциональность проекта.

Теперь ответим на самый главный вопрос: «Избавимся ли мы от Redux?» На самом деле полностью избавиться от Redux не получится, но в какой‑то мере, да, избавимся. Как? Во всех запросах, где используется react‑query/SWR использовать Redux не нужно, эти библиотеки сами все данные берут из бэкенда и работают в качестве “state manager”-а, а так же плюс к этому кешируют данные, что это даже очень выгодно.

Комментарии (14)


  1. dimonarhipon
    01.09.2023 14:11
    +1

    1. Я не понял почему сделан вывод что swr на больших проектах не применим.

    2. Хотелось бы раскрытие вопроса применения react-query vs swr в next


  1. DarthVictor
    01.09.2023 14:11

    SWR в свою очередь предоставляет только один хук — useSWR

    Нет. SWR предоставляет хук useSWRMutation. Чем он отличается от useMutation из react-query из статьи не очень понятно, если честно.


    1. ScorpAL
      01.09.2023 14:11

      Всё просто. Статья написана для руководителя автора. Так называемый доклад студента или практиканта.


  1. artalar
    01.09.2023 14:11

    Было бы интересно сравнение с https://www.reatom.dev/package/async/ :)


  1. noodles
    01.09.2023 14:11

    Всё никак не пойму популярность этих reаct-query\swr. Какие-то слишком замудрённые, а рекламируемый профит так себе. Честно пробовал прикрутить к домашнему проекту, плюнул и отказался через час:

    - обалдел когда увидел апи и кучу флажков, напрмиер, isFetching, isLoading, isIdle и куча тонкостей какой когда лучше использовать.

    - обалдел когда попытался по сабмиту сделать три параллельных запроса, и потом по результату например второго из них нужно сделать\или не сделать четвёртый запрос. Оно меня отправляет в dependent-queries. Вместо async\await сверху вниз - код становится какой-то ужасный.. сплошные use.. use..

    - не получается делать запросы вне jsx-компонента без use (у меня проект на mobx, поэтому вся логика в сторах, а реакт просто шаблонизатор). Оно конечно предлагает использовать queryClient.fetchQuery,но как я понял теряются многие рекламируемые плюшки.

    Может всё-таки мало времени уделил.


    1. Ashot
      01.09.2023 14:11

      Да причина популярности проста - упрощение работы с серверными данными. После хранения сервеных данных в редаксе это прям глоток воздуха.

      обалдел когда увидел апи и кучу флажков...

      В большинстве случаев достаточно использовать isLoading.

      обалдел когда попытался по сабмиту сделать три параллельных запроса

      Если речь про мутиции, то есть метод mutateAsync, который возвращает Promise и работает с async/await.

      Оно конечно предлагает использовать queryClient.fetchQuery,но как я понял теряются многие рекламируемые плюшки.

      Плюшки не теряются. queryClient.fetchQuery так же как и useQuery(собственно под капотом и вызывается .fetchQuery) сохраняет данные в кеше. Вызываем queryClient.fetchQuery вне компонента, внутри компонента имеем доступ к данным по ключу через useQuery.


  1. Andy_Francev
    01.09.2023 14:11

    Ну, с появлением RTK-Query, вопрос: "Избавимся ли мы от Redux?" потерял свою актуальность.


    1. Ashot
      01.09.2023 14:11

      Rtk-query всё равно уступает react-query. Rtk требует настроек слайса, потом ещё стора. Да, в стор надо добавить несколько строк, но это всё равно лишние телодвижения. Для React-query же по сути требуется ключ и запрос.
      Один раз довелось пощупать rtk-query - не впечатлило. React-query one love


  1. LyuMih
    01.09.2023 14:11

    Есть состояние запросов - RTK, SWR и т.п.
    Есть состояние приложения - Redux, MobX и т.п.

    Когда в проекте начинаются различаться эти вещи, избавиться от Redux и заменить его на React.useState, если ненадо шарить между компонентами запро с и React.Context или zustan (или другой stm) становится легче.

    Раньше на проектах часто сваливави все состояния запросов в Redux и он становился ещё большей помойкой)

    p.s. не везде всё клали в Redux)


  1. kenakula
    01.09.2023 14:11

    Не очень понятно почему, все-таки, при большом проекте нужно использовать react-qury.


  1. ratibordas
    01.09.2023 14:11

    Думал, открою статью и там будет что-то полезное, вроде опыта использования обеих библиотек в проде, или пример переписывания проекта с Redux на чисто серверный стейт. Но тут как всегда, ничего интересного, я бы и в доке мог это прочитать.

    Мне React Query нравится, особенно рефетч и возможность все запросики делать через defaultQueryFn, что позволяет удобненько в среде реакта обрабатывать ошибки, саму дату и много чего еще делать. Здорово, но никаких киллер фичей я не заметил. Хорошая дока, хорошо тестируется ( в доке есть пример с react testing library), хорошо кастомизируется. Это мы берем

    Если ближе к реальности, то в рф как-то query-библиотеки еще не прижились, тех лиды и прочие собеседующие не понимают, о чем ты говоришь в ответ на восторженные реплики "так это же в React Query в две строчки делается". Можно стартануть новый проект с этой библиотекой, но в абсолютном большинстве случаев мы работаем с кучей легаси кала, где даже тестов / доки нет, так что интегрировать наверно того не стоит, хотя это и очень удобно.


  1. string15
    01.09.2023 14:11

    Я не понял, как он может заменить редакс, вы вероятно из тех кто кладет данные из бэка в стэйт менеджер?


  1. iurii_gudkov
    01.09.2023 14:11

    React-query очень нишевая библиотека удобная только на проектах где нужно дернуть ручку и показать дынные. Если чуть более сложно то возникают все новые и новые приколы.

    Она скорее не облегчает работу, а меняет ее. Синхронизировать работу хуков между собой то еще удовольствие, высок риск иметь неконсистентный результат. Плюс все еще нужен стор, а это уже 2 места хранения данных и новые риски не консистентности.

    Так же жесткий биндинг кода к вьюшкам (посути начинаем писать код во вьюшках), а это уже антипаттерн. Проектов с кодом (бизнес логикой) в компонентах много и без этого, конечно, и как правило там лютый треш и гавнокод получается, даже если хотелось сделать "правильно". Зато потом можно статейки на хабре написать как героически командой перезжали пол года с либы на либу, с фреймворка на фреймворк.


  1. alexkomarchev
    01.09.2023 14:11

    Это нельзя назвать инструментами управления состояния. В первую очередь такого рода либы нужно для кеширования.