Архітектура та Best Practices
Архітектура та Best Practices
Ми вивчили API. Тепер поговоримо про те, як не перетворити проект на смітник. TanStack Query дає багато свободи, але "з великою силою приходить велика відповідальність".
Ось правила, які використовують професійні команди.
1. Кастомні Хуки — Це Закон
Ніколи не викликайте useQuery прямо в UI компонентах (якщо це не прототип на коліні).
Чому?
- Приховування деталей реалізації: Компонент не має знати про
queryKeyабоstaleTime. - Повторне використання: Якщо вам треба отримати користувача в Header і в Sidebar, ви просто викликаєте
useUser(). - Легкий рефакторинг: Змінився ключ? Змінилась логіка? Ви правите це в одному місці.
// ❌ Погано: Компонент знає занадто багато
function UserProfile() {
const { data } = useQuery({ queryKey: ['user'], queryFn: fetchUser });
// ...
}
// ✅ Добре: Компонент просто просить дані
function UserProfile() {
const { data } = useUser();
// ...
}
// hooks/useUser.ts
export const useUser = () => {
return useQuery({
queryKey: userKeys.me(),
queryFn: api.getUser,
staleTime: 1000 * 60 * 30, // Ми вирішили, що юзер не змінюється часто
});
};
2. Фабрики Ключів (Query Key Factories)
Ми згадували це в розділі 3, але це варто повторити. Хаос у ключах — головна причина багів інвалідації.
Використовуйте бібліотеку @lukemorales/query-key-factory або пишіть об'єкти вручну.
const todoKeys = {
all: ['todos'] as const,
lists: () => [...todoKeys.all, 'list'] as const,
list: (filters: string) => [...todoKeys.lists(), { filters }] as const,
details: () => [...todoKeys.all, 'detail'] as const,
detail: (id: number) => [...todoKeys.details(), id] as const,
};
3. Розділення Шарів (Layered Architecture)
Чітко розділяйте відповідальність:
- API Layer (
api/todos.ts): Чисті функції, які роблятьfetch/axiosі повертають Promise. Ніякого React. - Query Layer (
hooks/useTodos.ts): Кастомні хуки, які використовують API функції та додають логіку кешування (useQuery). - UI Layer (
components/TodoList.tsx): Використовує хуки та рендерить JSX.
4. Глобальна Обробка Помилок
Замість того, щоб перевіряти isError у кожному компоненті, використовуйте QueryCache global callbacks для тостів, та Error Boundaries для UI.
// queryClient.ts
const queryClient = new QueryClient({
queryCache: new QueryCache({
onError: (error) => {
toast.error(`Something went wrong: ${error.message}`);
},
}),
});
В компонентах:
// Якщо ви використовуєте useSuspenseQuery, помилка "спливе" до найближчого ErrorBoundary
function App() {
return (
<ErrorBoundary fallback={<div>Something broke!</div>}>
<Suspense fallback={<div>Loading...</div>}>
<UserProfile />
</Suspense>
</ErrorBoundary>
);
}
5. Тестування
Не тестуйте TanStack Query. Він протестований авторами. Тестуйте ваші хуки та інтеграцію.
Для тестів створіть окремий queryClient з вимкненими retry (щоб тести не чекали вічність при помилках).
const createTestQueryClient = () => new QueryClient({
defaultOptions: {
queries: {
retry: false, // Важливо для тестів!
},
},
});
test('renders todos', async () => {
render(
<QueryClientProvider client={createTestQueryClient()}>
<TodoList />
</QueryClientProvider>
);
// ...
});
Висновок
TanStack Query — це потужний інструмент, який при правильному використанні робить ваш код чистішим, а додаток — швидшим.
Чек-лист професіонала:
- Всі запити в кастомних хуках.
- Ключі зібрані в Key Factory.
-
staleTimeналаштовано глобально та перевизначено локально де треба. - Використовуються
DevTools. - Мутації автоматично інвалідують пов'язані запити.
Вітаємо! Ви пройшли курс майстерності TanStack Query. Тепер йдіть і видаліть весь цей useEffect код зі своїх проектів! 🚀
Просунуті Патерни та Оптимізація
Ви вже вмієте робити базові речі. Тепер перейдемо до технік "чорного поясу". Ці патерни допоможуть вирішити складні архітектурні завдання та оптимізувати продуктивність.
Server-Side Rendering (SSR) та Гідратація
Якщо ви використовуєте Next.js, Remix або Astro, ви хочете, щоб ваші дані завантажувалися на сервері для SEO та швидкого першого відтворення (LCP).