Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Библиотеки загрузки данных

Хук useFetch из урока о собственных хуках решает простую задачу. В настоящем приложении требований больше: не загружать одну и ту же статью дважды, обновлять данные при возвращении на вкладку, повторять неудачный запрос. Писать всё это вручную долго, поэтому используют библиотеки загрузки данных. Они хранят ответы в кэше — памяти, откуда данные отдаются сразу, без нового запроса.

Популярные библиотеки

БиблиотекаОсобенность
TanStack QueryСамая распространённая, работает с любым способом запроса
SWRПохожая идея, более компактный API
RTK QueryВстроена в Redux Toolkit

Дальше — пример на TanStack Query (версия 5).

Установка и подключение

npm install @tanstack/react-query

Приложение оборачивают в провайдер с клиентом запросов — в src/main.jsx:

// src/main.jsx
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
// импорты StrictMode, createRoot, BrowserRouter и App — как раньше
 
const queryClient = new QueryClient();
 
createRoot(document.getElementById('root')).render(
  <StrictMode>
    <QueryClientProvider client={queryClient}>
      <BrowserRouter>
        <App />
      </BrowserRouter>
    </QueryClientProvider>
  </StrictMode>,
);

QueryClient хранит кэш всех запросов приложения.

Запрос с useQuery

Перепишем список статей — src/components/PostList.jsx:

// src/components/PostList.jsx
import { useQuery } from '@tanstack/react-query';
import { Link } from 'react-router';
 
async function fetchPosts() {
  const response = await fetch('https://jsonplaceholder.typicode.com/posts');
  if (!response.ok) throw new Error(`Ошибка ${response.status}`);
  return response.json();
}
 
export default function PostList() {
  const { data, isPending, error } = useQuery({
    queryKey: ['posts'],
    queryFn: fetchPosts,
  });
 
  if (isPending) return <p>Загрузка…</p>;
  if (error) return <p>Ошибка: {error.message}</p>;
 
  return (
    <ul>
      {data.map((post) => (
        <li key={post.id}>
          <Link to={`/posts/${post.id}`}>{post.title}</Link>
        </li>
      ))}
    </ul>
  );
}

queryFn — функция, которая загружает данные и бросает ошибку при неудаче. queryKey — ключ, под которым ответ лежит в кэше. Откройте статью и вернитесь на главную: список появится сразу, без «Загрузка…», — он взят из кэша и тихо обновлён в фоне.

Ключ с параметром

Если запрос зависит от параметра, параметр кладут в ключ:

// src/pages/PostPage.jsx
const { id } = useParams();
const { data: post, isPending } = useQuery({
  queryKey: ['posts', id],
  queryFn: () =>
    fetch(`https://jsonplaceholder.typicode.com/posts/${id}`).then((r) => r.json()),
});

Для каждой статьи будет своя запись в кэше: ['posts', '1'], ['posts', '2']. Повторный переход на уже открытую статью покажет её мгновенно.

Что ещё умеет библиотека

ВозможностьКак называется
Отправка данных на серверuseMutation
Сброс кэша после измененияqueryClient.invalidateQueries
Повтор неудачного запросаВключён по умолчанию, 3 попытки

Частая ошибка

Если параметр запроса не попал в ключ, библиотека считает все запросы одним и показывает чужие данные:

// Неправильно: у всех статей один ключ.
useQuery({ queryKey: ['post'], queryFn: () => fetchPost(id) });
 
// Правильно:
useQuery({ queryKey: ['post', id], queryFn: () => fetchPost(id) });

Всё, от чего зависит queryFn, должно быть в queryKey.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.