TanStack Query надзвичайно швидкий "з коробки". Але якщо ви рендерите тисячі елементів або маєте складні дані, варто розуміти, як він працює під капотом.
Починаючи з v4, опція notifyOnChangeProps за замовчуванням встановлена в 'tracked'. Це магія.
Query створює Proxy навколо результату. Він "слухає", до яких полів ви звертаєтесь під час рендеру.
function User() {
const { data } = useQuery({ queryKey: ['user'], queryFn: fetchUser });
// Ми читаємо ТІЛЬКИ data.
// Ми НЕ читаємо isFetching, isError, error.
return <div>{data.name}</div>;
}
Якщо в фоні зміниться isFetching (наприклад, почався refetch), цей компонент НЕ перерендериться, тому що він не використовує це поле.
Це колосальна оптимізація. Раніше кожен компонент рендерився двічі на кожен запит (start -> success). Тепер — тільки якщо змінились дані.
const { data } = ...) — це не просто стиль, це спосіб підказати Query, що нам потрібно.Уявіть, що ви отримуєте JSON:
{ "id": 1, "todos": [{ "text": "A" }, { "text": "B" }] }
Через хвилину ви робите refetch, і приходить той самий JSON.
oldData === newData буде false, тому що це новий об'єкт з мережі. React зробить ререндер.
TanStack Query використовує техніку Structural Sharing: Він порівнює старий і новий об'єкт глибоко.
Результат: useQuery повертає стабільне посилання. useEffect і useMemo, які залежать від data, не перезапускаються.
selectМи вже говорили про select, але це головний інструмент для performance tuning.
const { data: todoCount } = useQuery({
queryKey: ['todos'],
queryFn: fetchTodos,
select: (todos) => todos.length, // Повертає число
});
Якщо в список додали елемент — компонент оновиться.
Але якщо в одному з todo змінився текст (а довжина масиву та сама) — компонент не оновиться! Тому що select повернув те саме число (якщо ви використовуєте useCallback для select, або якщо це примітив).
Ви можете зберігати кеш в localStorage або AsyncStorage (React Native), щоб при перезавантаженні сторінки дані з'являлися миттєво (навіть без мережі).
Це називається Offline Support.
import { persistQueryClient } from '@tanstack/react-query-persist-client';
import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister';
const persister = createSyncStoragePersister({
storage: window.localStorage,
});
persistQueryClient({
queryClient,
persister,
maxAge: 1000 * 60 * 60 * 24, // Зберігати добу
});
useQuery для тих самих даних. Завдяки дедуплікації це дешево.select для підписок на частини даних.Tracked Queries — вони зроблять більшість роботи за вас.queryFn та options (виносьте їх за межі компонента).