Що робить React Query (TanStack Query)?
Коротко:
React Query (TanStack Query) - це "розумний менеджер серверних даних" для React, який бере на себе все: завантаження, кеш, рефетч, помилки, синхронізацію, оптимістичні оновлення тощо.
Він робить роботу з API реактивною, швидкою і безпечною, без ручного
useEffectіuseState.
Що робить React Query (TanStack Query)
React Query - це "клієнт даних", який керує завантаженням, кешуванням, оновленням і синхронізацією даних у React-застосунках.
Тобто:
- ти описуєш як отримати дані (queryFn) і що це за дані (queryKey),
- а React Query сам:
- робить запит;
- кешує результат;
- оновлює UI при зміні даних;
- повторно валідує кеш;
- керує станами "loading", "error" і "stale";
- синхронізує все при фокусі вікна, перемиканні вкладок тощо.
Коротко: "Server state manager"
React Query не замінює Redux / Zustand, тому що він не для client state (стану інтерфейсу), а для server state - даних, отриманих з API.
| Тип стану | Приклад | Де зберігати |
|---|---|---|
| Client state | modal відкрита/закрита, обрана вкладка | useState / Redux / Zustand |
| Server state | користувачі, пости, замовлення, товари | React Query |
Приклад базового використання
import { useQuery } from "@tanstack/react-query";
function UserProfile({ id }) {
const { data, isLoading, error } = useQuery({
queryKey: ['user', id],
queryFn: () => fetch(`/api/users/${id}`).then(res => res.json()),
});
if (isLoading) return <p>Loading...</p>;
if (error) return <p>Error loading user</p>;
return <p>{data.name}</p>;
}React Query:
- один раз робить
fetch(); - кешує результат за ключем
['user', id]; - якщо компонент демонтується і знову з'явиться - дані вже будуть у кеші, без повторного запиту;
- якщо фокус повернеться у вікно -> автоматично оновить дані.
Основні фічі
1. Кешування даних
React Query кешує дані в пам'яті (QueryClient) з гнучкими налаштуваннями:
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>Параметри:
useQuery({
staleTime: 5 * 60 * 1000, // 5 хвилин вважаються актуальними
cacheTime: 10 * 60 * 1000, // через 10 хв кеш видаляється з пам'яті
});2. Stale-While-Revalidate
Показує кешовані (stale) дані миттєво, а паралельно робить запит за свіжими і оновлює UI після.
-> UX без "мигання" лоадерів.
3. Refetch on focus / reconnect
Якщо користувач згорнув вкладку, а потім повернувся:
- React Query автоматично перезапитує дані (якщо вони "застаріли").
<QueryClientProvider client={new QueryClient({
defaultOptions: { queries: { refetchOnWindowFocus: true } }
})}>4. Deduplication (дедуплікація запитів)
Якщо два компоненти викликають той самий запит:
useQuery({ queryKey: ['user', 1], queryFn: fetchUser });
useQuery({ queryKey: ['user', 1], queryFn: fetchUser });- React Query виконає тільки один запит, а обидва компоненти отримають однакові дані з кешу.
5. Mutations (POST / PUT / PATCH / DELETE)
Для зміни даних є useMutation():
import { useMutation, useQueryClient } from '@tanstack/react-query';
function UpdateUserButton({ id }) {
const queryClient = useQueryClient();
const updateUser = useMutation({
mutationFn: (data) => fetch(`/api/users/${id}`, {
method: 'PATCH',
body: JSON.stringify(data),
}),
onSuccess: () => {
// Після успішного оновлення інвалідуємо кеш
queryClient.invalidateQueries(['user', id]);
},
});
return (
<button onClick={() => updateUser.mutate({ name: 'Alex' })}>
Update
</button>
);
}6. Optimistic updates (оптимістичні оновлення)
Миттєво оновлює UI до відповіді сервера, а при помилці - відкочує.
const mutation = useMutation({
mutationFn: likePost,
onMutate: async (postId) => {
await queryClient.cancelQueries(['post', postId]);
const prev = queryClient.getQueryData(['post', postId]);
queryClient.setQueryData(['post', postId], old => ({
...old, likes: old.likes + 1
}));
return { prev };
},
onError: (_, postId, ctx) => {
queryClient.setQueryData(['post', postId], ctx.prev);
},
onSettled: (postId) => {
queryClient.invalidateQueries(['post', postId]);
},
});7. Pagination, Infinite scroll, Prefetch
Вбудована підтримка пагінації і підвантаження сторінок:
useInfiniteQuery({
queryKey: ['posts'],
queryFn: ({ pageParam = 1 }) => fetch(`/api/posts?page=${pageParam}`).then(r => r.json()),
getNextPageParam: (lastPage) => lastPage.nextPage,
});8. Persist кешу
Можна зберігати кеш між сесіями:
import { persistQueryClient } from '@tanstack/react-query-persist-client';
persistQueryClient({
queryClient,
persister: createSyncStoragePersister({ storage: window.localStorage }),
});-> при перезавантаженні дані не втрачаються, запити не повторюються.
Як це виглядає концептуально
React Query бере на себе:
ручний fetch()
useEffect()
useState()
стан loading / error / success
кешування та інвалідування
повторні запити при фокусі
все автоматичноКлючові концепції
| Термін | Що це |
|---|---|
| Query | Читання даних (GET) |
| Mutation | Зміна даних (POST, PUT, DELETE) |
| Query Key | Унікальний ідентифікатор запиту в кеші |
| Query Function | Функція, що виконує запит |
| Query Client | Центральний менеджер кешу |
| Invalidation | Оновлення кешу після змін |
| Stale Time | Час, поки дані вважаються свіжими |
| Cache Time | Час, після якого дані видаляються з пам'яті |
Підсумок
| Можливість | Що робить React Query |
|---|---|
| Автоматичні запити | робить і повторює fetch |
| Кешування | зберігає дані за ключем |
| Оновлення даних | refetch при фокусі/зміні |
| Керування станами | isLoading, isError, isFetching, data |
| Оптимістичні оновлення | миттєвий UI-відгук |
| Інвалідація кешу | оновлює після mutation |
| Deduplication | один запит - декілька компонентів |
| Persist кешу | між вкладками/сесіями |
| Infinite Scroll / Pagination | готові хуки |
| Без зайвого boilerplate | без useEffect/useState для запитів |
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.