React Query - библиотека для получения, кэширования, синхронизации и обновления “серверного” состояния в React-приложениях.
yarn add react-query
# или
npm i react-query
Ключевыми концепциями React Query
являются:
- Запросы (queries)
- Мутации (mutations)
- Инвалидация (аннулирование, признание недействительным) запроса (query invalidation), его кэша
Библиотека react-query
позволяет работать запросами к серверу, предоставляет доступ данным, позволяет задавать порядок запросов.. Однако для того чтобы с этим работать надо разделить весь стэйт который есть в redux на 2 части. Первая — это как раз данные, полученные с сервера. Вторая — это все остальное.
Подключается примерно так:
import { QueryClient, QueryClientProvider } from 'react-query';
import { ReactQueryDevtools } from 'react-query/devtools';
import { CitiesProvider } from './store/cities/cities-provider';
const queryClient = new QueryClient();
ReactDOM.render(
<React.StrictMode>
<QueryClientProvider client={queryClient}>
<CitiesProvider>
<App />
Простой пример использования:
const queryCities = useQuery("cities", fetchCitiesFunc)
const cities = queryCities.data || []
Первый параметр 'cities'
это ключ строка, которая должна быть уникальной для каждого запроса. Второй - это функция, которая возвращает Promise, который резолвит данные или отдает ошибку. Также можно передать третьим параметром объект с настройками.
useQuery()
возвращает объект UseQueryResult()
, который содержит данные о состоянии запроса, ошибку или данные
const { isLoading, isIdle, isError, data, error } = useQuery(..
Для выполнения последовательных запросов мне показалось удобным написать отдельный хук
export function useCurrentWeather(): WeatherCache {
const { currentCity } = useContext(СitiesContext);
// запрашиваем список городов
const queryCities = useQuery('cities', fetchCitiesFunc, {
refetchOnWindowFocus: false,
staleTime: 1000 * 60 * 1000,
});
const citiesRu = queryCities.data || [];
// ищем идентификатор текущего города..
const city = citiesRu.find((city) => {
if (city === undefined) return false;
const { id: elId } = city;
if (currentCity === elId) return true;
return false;
});
const { id: weatherId } = city ?? {};
// запрашиваем текущую погоду
const queryWeatherCity = useQuery(
['weatherCity', weatherId],
() => fetchWeatherCityApi(weatherId as number),
{
enabled: !!weatherId,
staleTime: 5 * 60 * 1000,
},
);
const { coord } = queryWeatherCity.data ?? {};
// запрашиваем прогноз по координатам из предыд. запроса
const queryForecastCity = useQuery(
['forecastCity', coord],
() => fetchForecastCityApi(coord as Coord),
{
enabled: !!coord,
staleTime: 5 * 60 * 1000,
},
);
return {
city,
queryWeatherCity,
queryForecastCity,
};
}
У react-query
есть возможность вывести окошко инструментов разработчика. Оно немного похоже на окно Redux, но появляется в виде фиксированного окошка поверх приложения(можно закрыть и останется только кнопка)
useQueries
позволяет динамически формировать массив запросов. Это нужно т.к. мы не можем опционально вызывать хукиuseQuery
.
const userQueries = useQueries(
users.map(user => {
return {
queryKey: ['user', user.id],
queryFn: () => fetchUserById(user.id),
}
})