JavaRush /Курсы /Модуль 3: React /Использование кэширования для оптимизации запросов

Использование кэширования для оптимизации запросов

Модуль 3: React
8 уровень , 7 лекция
Открыта

Почему кэширование так важно?

Вот вам аналогия. Представьте, что вы живёте в доме, в котором есть большая библиотека. Каждый раз, когда вам нужно перечитать книгу, вместо того чтобы идти в библиотеку, можно просто взять её с полки в вашей комнате. Экономия времени? Да! Так вот, эту комнатную полку можно сравнить с кэшированием данных в приложении.

Кэширование позволяет:

  • Уменьшить количество запросов к серверу и сэкономить трафик.
  • Ускорить время отклика приложения.
  • Повысить стабильность работы, показывая пользователю уже загруженные данные, даже если интернет-соединение пропадёт.

React Query делает кэширование "из коробки", но иногда есть смысл настроить его под конкретные задачи.

Основы кэширования в React Query

React Query автоматически кэширует результаты запросов. Это означает, что если вы отправляете одинаковый запрос повторно, данные возьмутся из кэша, а не с сервера, если их "свежесть" ещё актуальна. Давайте разберем, как это работает.

Кэширование и жизненный цикл данных

Каждый запрос в React Query имеет три состояния:

  1. Stale (устаревший) — данные, которые потенциально могут быть неактуальными.
  2. Fresh (свежий) — данные, которые актуальны и берутся из кэша.
  3. Garbage (удалённый) — данные, которые больше не нужны и удалены из кэша.

Управление временем жизни кэша

React Query предоставляет два параметра, которые управляют жизненным циклом данных:

  1. staleTime — время в миллисекундах, в течение которого данные считаются актуальными. Например, если staleTime установлен в 5000 мс, данные из кэша будут использоваться без дополнительного запроса в течение 5 секунд.
  2. cacheTime — время в миллисекундах, в течение которого данные остаются в кэше после того, как стали "устаревшими". По умолчанию это 5 минут.

Настройка staleTime и cacheTime

Переходим к практике. Предположим, у нас есть список пользователей, который не меняется часто. Мы можем увеличить staleTime и cacheTime, чтобы уменьшить количество запросов к серверу.

import {useQuery,  QueryClient,QueryClientProvider} from '@tanstack/react-query';

// Создаем QueryClient
const queryClient = new QueryClient();

// Компонент с запросом
function UserList() {
  const { data, isLoading, isError } = useQuery({
    queryKey: ['users'], // Новый формат ключа
    queryFn: async () => {
      const response = await fetch('https://jsonplaceholder.typicode.com/users');
      if (!response.ok) throw new Error('Ошибка при загрузке');
      return response.json();
    },
    staleTime: 10000, // 10 секунд
    cacheTime: 600000, // 10 минут
  });

  if (isLoading) return <p>Загрузка...</p>;
  if (isError) return <p>Ошибка загрузки данных.</p>;

  return (
    <ul>
      {data?.map((user: any) => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

export default function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <UserList />
    </QueryClientProvider>
  );
}

Пояснение:

  • staleTime: 10000 — если пользователь обновит список в течение 10 секунд, данные вернутся из кэша.
  • cacheTime: 600000 — данные сохраняются в кэше 10 минут после того, как истекло staleTime.

Такой подход особенно полезен для часто используемых данных, которые не меняются часто, например, списков товаров или профилей пользователей.

Оптимистичное обновление данных

Оптимистичное обновление — это ситуация, когда вы обновляете UI сразу, предполагая, что запрос к серверу выполнится успешно. Это особенно полезно для улучшения пользовательского опыта.

Приведем пример. Давайте добавим возможность удалить пользователя. При этом UI обновится моментально, не дожидаясь ответа от сервера.

import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';

function UserList() {
  const queryClient = useQueryClient();

  // Получение списка пользователей
  const { data, isLoading } = useQuery({
    queryKey: ['users'],
    queryFn: async () => {
      const response = await fetch('https://jsonplaceholder.typicode.com/users');
      if (!response.ok) throw new Error('Ошибка при получении пользователей');
      return response.json();
    },
  });

  // Мутация удаления пользователя с оптимистичным обновлением
  const mutation = useMutation({
    mutationFn: async (id: number) => {
      await fetch(`https://jsonplaceholder.typicode.com/users/${id}`, {
        method: 'DELETE',
      });
    },

    onMutate: async (id) => {
      // Отмена текущих запросов
      await queryClient.cancelQueries({ queryKey: ['users'] });

      // Сохраняем текущее состояние
      const previousUsers = queryClient.getQueryData<any[]>(['users']);

      // Оптимистичное обновление кэша
      queryClient.setQueryData<any[]>(['users'], (old) =>
        old ? old.filter((user) => user.id !== id) : []
      );

      return { previousUsers };
    },

    onError: (_err, _id, context) => {
      // В случае ошибки откат к предыдущему состоянию
      if (context?.previousUsers) {
        queryClient.setQueryData(['users'], context.previousUsers);
      }
    },

    onSettled: () => {
      // Повторно запрашиваем пользователей после завершения
      queryClient.invalidateQueries({ queryKey: ['users'] });
    },
  });

  if (isLoading) return <p>Загрузка...</p>;

  return (
    <ul>
      {data?.map((user: any) => (
        <li key={user.id}>
          {user.name}{' '}
          <button onClick={() => mutation.mutate(user.id)} disabled={mutation.isPending}>
            {mutation.isPending ? 'Удаление...' : 'Удалить'}
          </button>
        </li>
      ))}
    </ul>
  );
}

Пояснение:

  • Функция onMutate оптимистично обновляет список пользователей, сразу удаляя из UI того, кого хотят удалить.
  • Если запрос завершится с ошибкой, мы откатываем изменения с помощью onError.
  • onSettled используется для инвалидирования запроса и повторного получения данных.

Применение в реальных проектах

Эти техники могут быть полезны в следующих случаях:

  1. Каталоги и списки: для отображения продуктов или услуг, которые не изменяются каждую секунду.
  2. Личные кабинеты: данные пользователя, которые редко обновляются, но нужны при каждом входе.
  3. Оптимизация пользовательского опыта: для операций, требующих подтверждения на сервере (например, лайки, избранное).

Советы по настройке кэширования

  • Используйте большее значение staleTime для редко изменяемых данных.
  • Установите меньшее значение cacheTime для часто обновляемых данных.
  • Используйте onMutate для оптимистичных обновлений и минимизации задержек.
1
Задача
Модуль 3: React, 8 уровень, 7 лекция
Недоступна
Настройка кэширования с использованием `staleTime`
Настройка кэширования с использованием `staleTime`
1
Задача
Модуль 3: React, 8 уровень, 7 лекция
Недоступна
Использование параметра `cacheTime`
Использование параметра `cacheTime`
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ