Библиотека TanStack Query появилась как решение фундаментальной
проблемы фронтенд-разработки — сложности работы с серверным состоянием.
До её появления большинство приложений на React использовали комбинации
useEffect, useState, Redux, MobX или
собственных обёрток над fetch и axios для
получения данных с сервера.
Типичный код ранних React-приложений выглядел следующим образом:
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
setLoading(true);
fetch('/api/users')
.then(response => response.json())
.then(data => setUsers(data))
.catch(err => setError(err))
.finally(() => setLoading(false));
}, []);
Подобный подход создавал множество проблем:
Разработчики постепенно пришли к пониманию, что серверное состояние принципиально отличается от локального UI-состояния.
Локальное состояние:
const [isModalOpen, setIsModalOpen] = useState(false);
Серверное состояние:
const [users, setUsers] = useState([]);
имеет совершенно иную природу:
Именно эта концепция стала фундаментом будущего TanStack Query.
Создателем библиотеки стал Tanner Linsley. Изначально проект назывался React Query и был ориентирован исключительно на React.
Первая публичная версия библиотеки появилась примерно в 2019 году. Главная идея заключалась в создании декларативного API для работы с асинхронными данными.
Вместо ручного управления состоянием:
const [data, setData] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
разработчик получал готовую абстракцию:
const query = useQuery({
queryKey: ['users'],
queryFn: fetchUsers
});
Библиотека автоматически предоставляла:
query.data
query.isLoading
query.error
query.isFetching
query.refetch
Это radically изменило подход к серверному состоянию в React-приложениях.
На момент появления React Query экосистема React активно использовала Redux.
Однако Redux создавался прежде всего для клиентского состояния:
Многие разработчики начали хранить серверные данные в Redux:
{
users: [],
posts: [],
comments: [],
loading: false,
error: null
}
Со временем стало очевидно, что Redux плохо подходит для:
React Query предложил совершенно иной подход:
Серверное состояние не должно храниться как обычный state.
Эта идея стала переломной для frontend-разработки.
Первые версии React Query были относительно простыми. Основной функционал включал:
Пример раннего API:
const { data, status } = useQuery('users', fetchUsers);
Даже в ранних версиях библиотека уже поддерживала:
Это выделяло React Query среди большинства решений того времени.
Одной из важнейших инноваций библиотеки стало понятие stale data.
До появления React Query большинство приложений использовали два состояния:
Данные есть
Данных нет
React Query ввёл более сложную модель:
Fresh
Stale
Inactive
Garbage collected
Например:
useQuery({
queryKey: ['users'],
queryFn: fetchUsers,
staleTime: 5000
});
После загрузки данные считаются свежими (fresh) в
течение 5 секунд.
Затем они становятся устаревшими (stale), но продолжают
использоваться из кэша, одновременно инициируя фоновое обновление.
Эта модель существенно улучшила UX:
Одной из причин популярности React Query стала интеллектуальная система кэша.
Кэш строился вокруг ключей запросов:
['users']
['users', userId]
['posts', page]
Это позволило:
Например:
queryClient.invalidateQueries({
queryKey: ['users']
});
Подобная архитектура значительно превосходила традиционные Redux store-подходы.
Вторая версия библиотеки значительно улучшила API.
Появились:
Пример использования:
const query = useQuery(
['posts', page],
() => fetchPosts(page)
);
Именно во времена v2 библиотека начала активно набирать популярность.
React Query идеально совпал по времени с массовым распространением React Hooks.
До hooks работа с асинхронными данными часто выглядела громоздко:
class Users extends React.Component {
state = {
users: [],
loading: false
};
componentDidMount() {
this.loadUsers();
}
}
React Query стал естественным продолжением hook-экосистемы:
function Users() {
const query = useQuery({
queryKey: ['users'],
queryFn: fetchUsers
});
return <div>{query.data}</div>;
}
Библиотека оказалась очень хорошо адаптирована под функциональные компоненты.
Третья версия стала настоящим прорывом.
В v3 появились:
useInfiniteQuery({
queryKey: ['posts'],
queryFn: fetchPosts,
getNextPageParam: lastPage => lastPage.nextCursor
});
queryClient.prefetchQuery({
queryKey: ['users'],
queryFn: fetchUsers
});
useMutation({
mutationFn: updateUser,
onMutate: async (newUser) => {
await queryClient.cancelQueries(['users']);
}
});
const userQuery = useQuery({
queryKey: ['user'],
queryFn: fetchUser
});
const postsQuery = useQuery({
queryKey: ['posts', userQuery.data?.id],
queryFn: fetchPosts,
enabled: !!userQuery.data
});
Эти возможности превратили React Query из простой библиотеки загрузки данных в полноценную систему управления серверным состоянием.
В период активного развития React Query также появилась библиотека SWR от Vercel.
SWR использовала концепцию:
stale-while-revalidate
которая повлияла на развитие всей экосистемы data fetching.
Между React Query и SWR сформировалась своеобразная конкуренция:
| React Query | SWR |
|---|---|
| Более функционален | Более минималистичен |
| Богатый API | Простая концепция |
| Сложное кэширование | Лёгкая интеграция |
| Мутации | Простота |
| DevTools | Минимализм |
Конкуренция ускорила развитие обеих библиотек.
Со временем библиотека перестала быть исключительно React-ориентированной.
Появились адаптации для:
Это привело к глобальному ребрендингу:
React Query → TanStack Query
Название TanStack стало зонтичным брендом для целой экосистемы:
Ребрендинг решал сразу несколько задач.
Библиотека больше не зависела исключительно от React.
Появилась архитектура:
Core
Adapters
Например:
@tanstack/query-core
@tanstack/react-query
@tanstack/vue-query
Core-часть содержала основную логику:
Framework-адаптеры лишь связывали core с конкретным UI-фреймворком.
Версия v4 стала важнейшим архитектурным обновлением.
Основные изменения:
Старый пакет:
react-query
сменился на:
@tanstack/react-query
Был внедрён объектный синтаксис:
useQuery({
queryKey: ['users'],
queryFn: fetchUsers
});
вместо старого:
useQuery(['users'], fetchUsers);
Это позволило:
Одним из ключевых факторов успеха TanStack Query стала мощная поддержка TypeScript.
Пример автоматического вывода типов:
const fetchUsers = async (): Promise<User[]> => {
const response = await fetch('/api/users');
return response.json();
};
const query = useQuery({
queryKey: ['users'],
queryFn: fetchUsers
});
Тип query.data автоматически становится:
User[] | undefined
Со временем TypeScript-поддержка стала одной из лучших среди frontend-библиотек.
Постепенно библиотека сместилась к централизованной архитектуре через
QueryClient.
const queryClient = new QueryClient();
Он начал отвечать за:
Это сделало систему более масштабируемой.
Рост популярности SSR-фреймворков существенно повлиял на развитие TanStack Query.
Особенно важным стало развитие Next.js.
TanStack Query начал активно поддерживать:
Пример dehydration:
dehydrate(queryClient);
Hydration позволял избегать повторных запросов после SSR.
С развитием React Concurrent Features библиотека начала адаптироваться под Suspense.
Пример:
useSuspenseQuery({
queryKey: ['users'],
queryFn: fetchUsers
});
TanStack Query стал одной из первых крупных библиотек, активно поддерживающих новую архитектуру React.
Пятая версия стала очередным серьёзным обновлением.
Основные изменения:
Многие устаревшие возможности были удалены.
Была оптимизирована:
Библиотека улучшила механизмы:
Особое внимание уделялось:
TanStack Query перестал быть отдельной библиотекой и превратился в часть полноценной инфраструктуры frontend-разработки.
Появились:
Например:
persistQueryClient({
queryClient,
persister
});
Это позволило строить offline-first приложения.
TanStack Query существенно изменил подход к frontend-архитектуре.
До его появления:
Redux = универсальное решение
После:
Client State ≠ Server State
Эта концепция повлияла на:
Сегодня TanStack Query считается одним из стандартов работы с серверным состоянием.
Библиотека используется:
Основные причины популярности:
История TanStack Query — это история постепенного перехода от:
"библиотеки для запросов"
к:
"платформе управления серверным состоянием"
Ранние версии решали задачу загрузки данных.
Современные версии решают:
Это сделало TanStack Query одной из ключевых технологий современной frontend-разработки.