Введение
В React Query запросы называют "Query". Это не просто слово, а концепция, которая является основой управления данными в React Query. Идея проста: запросы должны быть декларативными и управляться из React-компонентов. Это означает, что мы описываем, какие данные нам нужны, а библиотека сама заботится об их извлечении и кэшировании.
React Query предоставляет хук useQuery, специально разработанный для выполнения запросов к API. Давайте разберём, как он работает.
Пример простого API-запроса с использованием useQuery
Предположим, у нас есть API, которое возвращает список пользователей: https://jsonplaceholder.typicode.com/users.
import { useQuery } from '@tanstack/react-query';
import axios from 'axios';
// Функция для получения данных от API
const fetchUsers = async () => {
const { data } = await axios.get('https://jsonplaceholder.typicode.com/users');
return data;
};
// Компонент, использующий React Query для получения данных
const Users = () => {
const { data, isLoading, isError, error } = useQuery({
queryKey: ['users'],
queryFn: fetchUsers,
});
if (isLoading) return <p>Загрузка данных...</p>;
if (isError && error instanceof Error) return <p>Ошибка: {error.message}</p>;
return (
<ul>
{data?.map((user: { id: number; name: string }) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
};
export default Users;
Разберём код по частям:
Функция получения данных
fetchUsers:- Здесь используется
axiosдля выполнения GET-запроса к API. - Функция возвращает данные от API.
- Здесь используется
Хук
useQuery:- Первый аргумент
'users'— это ключ запроса. Он используется для идентификации кэша данных. - Второй аргумент — это функция, которую React Query вызывает для получения данных
fetchUsers.
- Первый аргумент
Переменные состояния
useQuery:dataсодержит результат запроса.isLoadingпоказывает, находится ли запрос в стадии загрузки.isErrorиerrorпозволяют обработать ошибки.
Обработка состояний в компоненте:
isLoadingиisErrorпомогают нам отобразить соответствующие сообщения.- Если данные успешно загружены, мы отображаем их в виде списка.
Параметры и опции useQuery
React Query обладает множеством встроенных настроек, позволяя полностью контролировать поведение запросов.
Настройка поведения запросов
У хука useQuery есть третий аргумент — объект опций. Вот несколько популярных настроек:
enabled: указывает, должен ли запрос выполняться автоматически.refetchOnWindowFocus: перезагружать ли данные при переключении на вкладку (по умолчанию —true).staleTime: указывает, как долго данные считаются актуальными (в миллисекундах).
Вот пример с настройками:
const { data, isLoading, isError } = useQuery({
queryKey: ['users'],
queryFn: fetchUsers,
enabled: true, // Запрос запускается автоматически
refetchOnWindowFocus: false, // Отключаем повторное обновление при переключении вкладок
staleTime: 5000, // Данные считаются актуальными в течение 5 секунд
});
Обработка ошибок и состояния загрузки
Работая с React Query, важно правильно обрабатывать состояния загрузки и ошибки. Давайте улучшим наш предыдущий пример, добавив индикатор загрузки и больше информации при возникновении ошибки.
if (isLoading) {
return <div>⏳ Данные загружаются, потерпите чуть-чуть...</div>;
}
if (isError) {
return (
<div>
<p>😢 Что-то пошло не так.</p>
<p>Ошибка: {error.message}</p>
</div>
);
}
Теперь, если API вернёт ошибку, пользователь увидит не только сообщение, но и текст самой ошибки. Удобно для дебага и отличного UX!
Пример: реализация списка задач
Давайте применим знания на практике и создадим компонент для отображения списка задач. Наш API: https://jsonplaceholder.typicode.com/todos.
Код компонента
import { useQuery } from '@tanstack/react-query';
import axios from 'axios';
// Функция для получения списка задач
const fetchTodos = async () => {
const { data } = await axios.get('https://jsonplaceholder.typicode.com/todos');
return data;
};
// Компонент для отображения задач
const TodoList = () => {
const { data: todos, isLoading, isError, error } = useQuery({
queryKey: ['todos'],
queryFn: fetchTodos,
});
if (isLoading) return <p>Загрузка задач...</p>;
if (isError && error instanceof Error) return <p>Ошибка: {error.message}</pм;
return (
<ul>
{todos?.slice(0, 10).map((todo: { id: number; title: string }) => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
);
};
export default TodoList;
Что нового?
- Мы используем
data: todos, чтобы дать переменной более осмысленное название. - С помощью
slice(0, 10)отображаем только первые 10 задач. - Компонент получился компактным и декларативным благодаря React Query.
Запросы с динамическими параметрами
Иногда необходимо создавать запросы с динамическими параметрами. Например, получение пользователя по его id.
Пример запроса с параметром
import { useQuery } from '@tanstack/react-query';
import axios from 'axios';
const fetchUserById = async (id: number) => {
const { data } = await axios.get(`https://jsonplaceholder.typicode.com/users/${id}`);
return data;
};
const UserDetails = ({ userId }: { userId: number }) => {
const { data, isLoading, isError, error } = useQuery({
queryKey: ['user', userId],
queryFn: () => fetchUserById(userId),
enabled: Boolean(userId), // не запрашивать, если id невалиден
});
if (isLoading) return <p>Загрузка данных пользователя...</p>;
if (isError && error instanceof Error) return <p>Ошибка: {error.message}</p>;
return (
<div>
<h3>{data?.name}</h3>
<p>Email: {data?.email}</p>
</div>
);
};
export default UserDetails;
Объяснение динамического ключа
['user', userId]— это ключ, который указывает на уникальный запрос. ЗначениеuserIdпомогает React Query различать их.- Функция
() => fetchUserById(userId)позволяет передать параметр в запрос.
Практическое применение
Знать, как создавать запросы — это, конечно, круто, но зачем это нужно? На собеседовании знания о React Query могут выделить вас как разработчика, понимающего, как оптимизировать работу с серверными данными. В реальных проектах React Query позволяет создать эффективное приложение с кэшированием "из коробки". Например, в CRM-системе или интернет-магазине это может кардинально улучшить производительность.
Секрет успеха в React Query — концепция "Декларируй, что тебе нужно, а я уж сам разберусь!". Эта библиотека снимает необходимость ручного управления кэшем и состояниями, что экономит время и нервы.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ