Перш ніж ми напишемо хоч рядок коду з TanStack Query, нам потрібно змінити світогляд. Більшість React-розробників проходять через стадію, коли вони намагаються керувати всім станом однаково. Це пастка.
У цій главі ми розберемо фундаментальну відмінність між Client State та Server State, і чому спроба керувати ними одними й тими ж інструментами призводить до болю, багів та спагетті-коду.
У сучасному фронтенді ми керуємо двома принципово різними типами даних.
Це стан, який належить браузеру/додатку. Він синхронний, миттєвий і повністю під нашим контролем.
isModalOpen (чи відкрито модальне вікно)theme (темна/світла тема)formValues (що користувач ввів у інпут прямо зараз)activeTab (яка вкладка обрана)useState, useReducer, Context API, Zustand, Redux (для UI).Це дані, які належать серверу. Ми лише позичаємо їх для відображення.
useEffect — це погано для даних?Давайте розглянемо класичний приклад "наївного" фечингу даних, який пишуть 99% новачків (і навіть мідлів).
function ProductList() {
const [products, setProducts] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
setIsLoading(true);
try {
const res = await fetch('/api/products');
const data = await res.json();
setProducts(data);
} catch (err) {
setError(err);
} finally {
setIsLoading(false);
}
};
fetchData();
}, []);
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error!</div>;
return (/* рендер списку */);
}
Виглядає нормально? На перший погляд так. Але давайте подивимось, чого тут не вистачає для production-ready додатку:
id зміниться, і ми запустимо новий запит, поки попередній ще йде? Може статися так, що попередній запит (старий) прийде після нового, і ми перезапишемо актуальні дані старими. useEffect не має вбудованого механізму скасування (cancellation).Header, який показує кількість товарів, і ProductList, який показує самі товари, і вони монтуються одночасно — ви відправите два однакових запити на /api/products.useEffect ніколи про це не дізнається.useEffect — це пекло.Коли розробники розуміють, що useEffect у компонентах не масштабується, вони часто кидаються в іншу крайність: "Давайте покладемо все в Redux!".
І починається ера Thunks, Sagas або Epics.
Типовий потік в Redux для отримання даних:
FETCH_PRODUCTS_START.FETCH_PRODUCTS_SUCCESS.FETCH_PRODUCTS_ERROR.isLoading, data, error).useSelector в компоненті.useEffect для запуску Thunk.Результат: Тонни boilerplate-коду.
Але найгірше те, що Redux не знає, що це Server State. Для нього це просто об'єкт. Він не знає, коли дані "протухли". Він не вміє робити refetch при фокусі вікна. Ви починаєте писати власні милиці (костилі) для перевірки lastUpdated timestamp...
TanStack Query використовує стратегію кешування, популяризовану HTTP специфікацією (RFC 5861), яка називається Stale-While-Revalidate.
Суть проста:
Якщо дані змінилися — онови UI. Якщо ні — залиш як є.
Ефект для користувача: Додаток працює миттєво. Немає спіннерів при навігації "Назад/Вперед". Спіннери з'являються лише при першому завантаженні.
TanStack Query (React Query) — це бібліотека, яка реалізує цю логіку "з коробки". Вона бере на себе:
У наступному розділі ми встановимо бібліотеку та налаштуємо наше середовище для комфортної роботи.
TanStack Query: Майстерність Керування Станом Сервера
Ласкаво просимо до повного курсу з опанування TanStack Query (раніше відомого як React Query). Це не просто документація, це подорож від ручного фечингу даних до професійної архітектури синхронізації станів.
Встановлення та Налаштування: Фундамент
Правильний старт — половина успіху. У цій главі ми не просто встановимо бібліотеку, а налаштуємо її так, щоб вона працювала на нас, а не проти нас. Ми також підключимо DevTools — інструмент, без якого робота з TanStack Query нагадує ходіння в темряві.