Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Що робить React Query (TanStack Query)?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**React Query (TanStack Query)** - це "розумний менеджер серверних даних" для React, який бере на себе все: завантаження, кеш, рефетч, помилки, синхронізацію, оптимістичні оновлення тощо. **Ключове:** React Query не замінює Redux / Zustand, тому що він не для client state (стану інтерфейсу), а для server state - даних, отриманих з API.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення### Коротко: > **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 | --- ## Приклад базового використання ```javascript 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`) з гнучкими налаштуваннями: ```javascript <QueryClientProvider client={queryClient}> <App /> </QueryClientProvider> ``` Параметри: ```javascript 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 автоматично перезапитує дані (якщо вони "застаріли"). ```javascript <QueryClientProvider client={new QueryClient({ defaultOptions: { queries: { refetchOnWindowFocus: true } } })}> ``` --- ### 4. **Deduplication (дедуплікація запитів)** Якщо два компоненти викликають той самий запит: ```javascript useQuery({ queryKey: ['user', 1], queryFn: fetchUser }); useQuery({ queryKey: ['user', 1], queryFn: fetchUser }); ``` - React Query виконає **тільки один запит**, а обидва компоненти отримають однакові дані з кешу. --- ### 5. **Mutations (POST / PUT / PATCH / DELETE)** Для зміни даних є `useMutation()`: ```javascript 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 **до** відповіді сервера, а при помилці - відкочує. ```javascript 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** Вбудована підтримка пагінації і підвантаження сторінок: ```javascript useInfiniteQuery({ queryKey: ['posts'], queryFn: ({ pageParam = 1 }) => fetch(`/api/posts?page=${pageParam}`).then(r => r.json()), getNextPageParam: (lastPage) => lastPage.nextPage, }); ``` --- ### 8. **Persist кешу** Можна зберігати кеш між сесіями: ```javascript import { persistQueryClient } from '@tanstack/react-query-persist-client'; persistQueryClient({ queryClient, persister: createSyncStoragePersister({ storage: window.localStorage }), }); ``` -> при перезавантаженні дані не втрачаються, запити не повторюються. --- ## Як це виглядає концептуально React Query бере на себе: ```javascript ручний 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 для запитів |Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.