Skip to content

Reatom VS react-query

Posted on:21 апреля 2023 г. at 00:00

Reatom VS react-query

Краткое сравнение ключевых API и поведения в @tanstack/react-query и @reatom/async.

TL;DR:

Table of contents

Open Table of contents

Композиция и конфигурация

RQ позволяет включать или перенастраивать какие-то фичи с помощью существующих параметров. Reatom предоставляет примитивы с которыми разработчик может настроить что угодно.

// --- DATA FETCHING ---

// CONFIGURATION
export const useSomeQuery = () =>
  useQuery({
    queryKeys: ["some"],
    keepPreviousData: true,
    queryFn: async () => {
      /*  */
    },
    initialData: [],
    select: ({ data }) => data.filter(el => el.image_id),
    retry: (failureCount, error) =>
      failureCount < 5 ? failureCount ** 10 : -1,
  });

// COMPOSITION
export const fetchSome = reatomAsync(async () => {
  /*  */
}).pipe(
  withAbort(),
  withCache(),
  withDataAtom([], (ctx, { data }) => data.filter(el => el.image_id)),
  withRetry({
    onReject: (ctx, error, retries) => (retries < 5 ? retries ** 10 : -1),
  })
);
onConnect(fetchSome.dataAtom, fetchSome);
export const useSomeAtom = () => useAtom(fetchSome.dataAtom);

// --- DATA UPDATING ---

// CONFIGURATION (fails)
export const useSomeMutations = () => {
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: async () => {
      /*  */
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["some"] });
    },
  });
};

// COMPOSITION
export const updateSome = reatomAsync(async () => {
  /*  */
});
onUpdate(updateSome, fetchSome.invalidateCache);
export const useSomeUpdate = () => useAction(updateSome);

В примере выше видно, что useMutation не имеет нужной конфигурации и код управления каким-то, достаточно типовым, поведением приходится писать самому. В Reatom все есть Atom и мы можем легко настраивать нужное поведение с onUpdate, получая правильные батчинги и умное логирование.

Конфигурация проще

Какие плюсы конфигурации?

Композиция эффективнее

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

Что хорошего в композиции?

Разработчик библиотеки с конфигурацией должен всегда выбирать между гибкостью и сложностью: нужно либо очень много перегрузок, либо некоторые конфигурации будут невыразимы или принимать невозможные конфигурации (конфликтующие параметры). Пользователю библиотеки будет не очевидно с этим работать в не тривиальных случаях. На момент написания поста useQuery принимает два параметра retry и retryDelay, в каждом из которых можно указывать число или функцию. Есть ли в них отличие и что будет если указать оба параметра (такое может быть, при переиспользовании какой-то конфигурации)? При композиции каждая фича имеет отдельную небольшую конфигурацию - это гибче и проще в каждом отдельном случае.

Инстанциирование (work in progress)

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

https://tkdodo.eu/blog/breaking-react-querys-api-on-purpose

Цепочки (work in progress)

зависимые запросы очень примитивные https://tanstack.com/query/latest/docs/react/guides/dependent-queries

нет отмены цепочки запросов https://habr.com/ru/companies/ruvds/articles/725208/

проблема с саспенсом и параллельными запросами (актуально и для реатома в случае с onConnect?) (https://tanstack.com/query/latest/docs/react/guides/parallel-queries)

Производительность (work in progress)

@tanstack/react-query - 45.65KB -> 12.72KB (gzip)

@reatom/async - 8.04KB -> 3.24KB (gzip)