Как выполнять запросы в React с помощью TanStack useQuery
Хочу рассказать про простой хук useQuery от Tansak, который поможет вам облегчить работу при работе с запросами. Он стал очень поплурян в последние годы и его часто используют.
Давайте рассмотрим простой пример. У нас есть страница, где мы показываем список неких новостей. Соответственно, мы должны выполнить GET запрос в useEffect
, затем сохранить полученные новости в состояние.
Также нужно дополнительно создать состояние для ошибки и прелоадера (isLoading state). Т.е. это самый простой вариант, как без лишних библиотек выполнять запросы и показывать данные.
import { useEffect, useState } from 'react';
export default function NewsCategoryPage() {
const [error, setError] = useState(null);
const [isLoading, setIsLoading] = useState(false);
const [news, setNews] = useState(null);
useEffect(() => {
async function fetchNews() {
setIsLoading(true);
const response = await fetch('http://localhost:8080/news');
if (!response.ok) {
setError('Failed to fetch news.');
setIsLoading(false);
return;
}
const news = await response.json();
setNews(news);
setIsLoading(false);
}
fetchNews();
}, []);
if (isLoading) {
return <p>Loading...</p>;
}
if (error) {
return <p>Error: {error}</p>;
}
return (
<>
<h1>News Page</h1>
<NewsList news={news} />
</>
);
}
Да, это не трудно и можно вполне так делать, но для такого базового сценарий и весьма популярного, мы делаем слишком много действий, например 3 состояния, плюс еще useEffect. Понятно, что можно создать свой костомный хук или что-нибудь другое, но давайте рассмотрим useQuery, который помимо этого умеет еще много что. Давайте для начала, повторим эту логику на этом хуке.
import { useQuery } from '@tanstack/react-query';
export default function NewsCategoryPage() {
const { isPending, error, data } = useQuery({
queryKey: ['newsData'],
queryFn: () =>
fetch('http://localhost:8080/news').then((res) => {
if (!res.ok) {
throw new Error('Failed to fetch news.');
}
return res.json();
}),
});
if (isPending) {
return <p>Loading...</p>;
}
if (error) {
return <p>Error: {error.message}</p>;
}
return (
<>
<h1>News Page</h1>
<NewsList news={data} />
</>
);
}
PS: также нужно добавить провайдер для его работы в главном файле index.js или App.js
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
const queryClient = new QueryClient()
export default function App() {
return (
<QueryClientProvider client={queryClient}>
<ReactQueryDevtools />
<App/>
</QueryClientProvider>
)
}
Как мы видим, все это уже есть из коробки, без лишних состояний, useEffect, ручной обработке ошибок и загрузки. И для начала этого хватит для старта
Остальные возможности useQuery
Но это еще не все, этот хук имеет очень много возможностей. Давайте рассмотрим самое основное
Одно из ключевых фишек, это поддержка кэша. Т.е. если данные на сервере не изменились, то вместо выполнения запроса он будет идти в кэш и брать данные оттуда. Для этого он смотрим на queryKey
и другие параметры. И по вашему условиям он будет брать данные из кэша или выполнять запрос, рассмотрим подробнее.
staleTime: 10000
staleTime - Этот параметр говорит, что кэш актуален 10 секунд и нельзя чаще его запрашивать. Т.е. за 10 секунд будет только один запрос и не важно, сколько раз мы запросили данные, только после этого времени будет выполнен запрос при вызове
По умолчанию staleTime = 0, это значит, что данные сразу считаются устаревшими, и useQuery всегда будет стремиться обновить их, если компонент монтируется или окно получает фокус. Однако, сами данные кэшируются на 5 минут (cacheTime = 5 * 60 * 1000), и их можно повторно использовать, если они ещё не удалены.
cacheTime: 1000 * 60 * 10 // 10 минут
Это время жизни кэша, чтобы отключить кэш совсем нужно указать 0. По умолчанию 5 минут, это время, пока будут храниться данные в кэше, даже если компонент размонтирован
refetchInterval: 5000
refetchInterval - Этот параметр может облегчить многим жизнь, по сути это long-polling, т.е. будет выполняться запрос каждый 5 секунд. Это например удобно, если у нас очень часто меняются данные и нужно всегда показывать актуальными. Если нужно обновлять данные в реальном времени, то для сложных кейсов лучше использовать WebSocket или Server-Sent Events. Но для большинства задач refetchInterval — это простой и рабочий способ периодически получать свежие данные.
refetchOnWindowFocus: true // по умолчанию включено
refetchOnWindowFocus - Обновление данных при возвращении на вкладку браузера
Также можно удобно обновлять данные вручную, как пример:
const { isPending, error, data, refetch } = useQuery(...);
<button onClick={() => refetch()}>Обновить</button>
Что в итоге, useQuery - мощный и в то же время простой инструмент, который поможет вам с рутиной запросов:
- Автоматически кэширует данные
- Обновляет их по таймеру или при возврате во вкладку
- Делает код чище и удобнее
- Даёт гибкость — можно управлять кэшем, вручную рефетчить и настраивать поведение под себя
Оставить комментарий