Глибоке Занурення в Продуктивність
Глибоке Занурення в Продуктивність
TanStack Query надзвичайно швидкий "з коробки". Але якщо ви рендерите тисячі елементів або маєте складні дані, варто розуміти, як він працює під капотом.
Tracked Queries (Відстежування Властивостей)
Починаючи з 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, що нам потрібно.Structural Sharing (Структурне Спільне Використання)
Уявіть, що ви отримуєте 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, або якщо це примітив).
Persisters (Збереження Кешу)
Ви можете зберігати кеш в 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(виносьте їх за межі компонента).