Так что же такое React-запрос? Это волшебная библиотека, которая кэширует и обновляет ваши запросы, устраняя или, по крайней мере, уменьшая потребность в каком-либо сложном управлении состоянием. Большую часть времени вы обнаружите, что делаете запросы, обернутые их хуком useQuery — проще не бывает.

import { useQuery } from "react-query";
const { isLoading, error, data } = useQuery('repoData', async () =>
     const response = await fetch('https://api.github.com/repos/tannerlinsley/react-query')
    return response.json()
));

Вы можете найти библиотеку на Github по адресу https://github.com/tanstack/query.

Сравнение с MobX

Даже не вдаваясь в сферу Redux, который я лично считаю чрезвычайно тяжелым шаблоном, давайте сравним запрос React с MobX, библиотекой управления состоянием, которая была моей любимой в течение многих лет. На момент написания статьи он превзошел MobX на Github на 5 тысяч звезд, что является довольно большим достижением.

В качестве примера возьмем приложение с общедоступными профилями пользователей — например, LinkedIn.

С MobX у вас обычно есть своего рода хранилище для пользовательских данных. Возможно, один для хранения собственных пользовательских данных, токенов входа и тому подобного. Для других профилей у вас будет другой магазин, который вы будете повторно использовать для разных профилей. Если вы хотите кэшировать другие профили, вам обычно потребуется другое более сложное хранилище, в котором вы будете хранить другие данные профиля в некотором массиве.

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

Реагировать на запрос на помощь

С реагирующим запросом вы просто делаете запросы. Поместите их в кеш под динамическими ключами, чтобы все они кешировались по отдельности. Запрос React уже предоставляет вам помощники по разбивке на страницы, так что у вас все хорошо. Количество шаблонов? Практически ноль. И лучшая часть? Каждый раз, когда вы попадали на страницу с useQuery, она автоматически обновлялась в фоновом режиме. И вы даже можете контролировать, как часто это происходит. Вы также можете настроить количество повторных попыток, если ваш сервер будет «занят» (не то чтобы вы должны это разрешать, но кто знает :-)) или плохое сетевое соединение.

Пример профиля пользователя со списком его занятий с бесконечной разбивкой на страницы будет выглядеть примерно так:

import { useQuery } from "react-query";
const ownUserId = 'random-uuid' // own user ID, you'd typically store this in local storage
    
// list user data
const { data: user } = useQuery(
    [`user-data`, userId],
    () => userService.getById(userId),
    { cacheTime: 
        ownUserId === userId ? Infinity : 1000 * 60 * 5 
    } // cache thyself for a long time
);
// list user employments
const {
    data,
    refetch,
    fetchNextPage,
    isFetching,
    hasNextPage,
    isLoading,
} = useInfiniteQuery(
    [`user-employments`, userId],
    ({ pageParam = 1 }) =>
      employmentService.listEmployments({
        page: pageParam,
      }),
    {
      getNextPageParam: (lastPage, pages) => (lastPage.length > 0 ? pages.length + 1 : undefined),
    }
);
const employments = flatten(data?.pages || []);

Вот и все. Кэшируется. По умолчанию на 5 минут. Он обновится, когда вы зайдете в профиль пользователя. У вас есть куча вспомогательных функций для таких вещей, как обновление всех данных и логические значения, чтобы указать статус того, что делает реагирующий запрос.

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

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

import { useQueryClient } from "react-query";
const queryClient = useQueryClient();
const onConnect = async (userId: string): Promise<void> => {
    await connectService.connectToUser(userId);
    // invalidate the query, meaning it should refetch (if mounted, immediately)
    queryClient.invalidateQueries(["user-data", userId]);
   // or mutate the query, eliminating the need for a refetch
   queryClient.setQueryData(
        ["user-data", userId], 
        (prevUser: User) => ({ ...prevUser, connected: true })
    );
};

Если к концу этого поста вы не станете его поклонником, я призываю вас попробовать. Тебе это понравится.