JavaRush /Курсы /Модуль 3: React /Управление кэшем данных и его обновление

Управление кэшем данных и его обновление

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

Зачем вам нужно управление кэшем?

Итак, представьте, что ваш React-приложение — это ресторан. Если ваш сервер — это кухня, то кэш — это холодильник, где хранятся готовые блюда, чтобы их быстро раздать без повторного приготовления (то бишь запроса к серверу). Управление кэшем позволяет:

  • Снизить нагрузку на сервер (зачем запрашивать одно и то же по 100 раз?).
  • Ускорить отображение данных для пользователя (вот вам запрошенный ранее бургер, приятного аппетита!).
  • Улучшить пользовательский опыт (никто не любит ждать).

React Query автоматически кэширует данные запросов, но иногда у нас есть специфические требования. Например, заставить данные обновляться быстрее или синхронизироваться с другими изменениями в приложении.

Как React Query управляет кэшем?

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

Основные параметры, которые помогают контролировать кэш:

  1. staleTime — время, в течение которого данные считаются свежими (по умолчанию 0).
  2. cacheTime — время, в течение которого данные остаются в кэше, даже если больше не используются (по умолчанию 5 минут).

Обновление данных в кэше

Зачастую вам нужно вручную обновить кэш для синхронизации со статусом вашего приложения. React Query предоставляет удобные функции для этого:

Использование QueryClient.setQueryData

Метод setQueryData позволяет обновить данные определённого запроса в кэше без взаимодействия с сервером. Это называется оптимистичным обновлением — вы предполагаете, что результат операции успешен, и обновляете интерфейс заранее. Если сервер вернёт ошибку, данные можно откатить.

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

// Пример API-функции
const fetchTodo = async (id: number) => {
  const response = await fetch(`/api/todos/${id}`);
  if (!response.ok) throw new Error('Ошибка при получении задачи');
  return response.json();
};

const updateTodo = async (todo: { id: number; title: string }) => {
  const response = await fetch(`/api/todos/${todo.id}`, {
    method: 'PUT',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(todo),
  });
  if (!response.ok) throw new Error('Ошибка при обновлении задачи');
  return response.json();
};

const TodoComponent = ({ id }: { id: number }) => {
  const queryClient = useQueryClient();

  // Получение данных Todo
  const { data: todo } = useQuery({
    queryKey: ['todo', id],
    queryFn: () => fetchTodo(id),
  });

  // Мутация для обновления Todo
  const mutation = useMutation({
    mutationFn: updateTodo,

    onMutate: async (updatedTodo) => {
      // Отменяем любые исходящие запросы для этого Todo
      await queryClient.cancelQueries({ queryKey: ['todo', id] });

      // Сохраняем прежние данные для возможного отката
      const previousTodo = queryClient.getQueryData(['todo', id]);

      // Обновляем кэш с новыми данными (оптимистично)
      queryClient.setQueryData(['todo', id], updatedTodo);

      // Возвращаем прежние данные для возможного отката
      return { previousTodo };
    },

    onError: (error, updatedTodo, context) => {
      // Откат изменений в случае ошибки
      if (context?.previousTodo) {
        queryClient.setQueryData(['todo', id], context.previousTodo);
      }
    },

    onSettled: () => {
      // Повторно загружаем данные с сервера после завершения мутации
      queryClient.invalidateQueries({ queryKey: ['todo', id] });
    },
  });

  return (
    <div>
      <h3>{todo?.title}</h3>
      <button
              onClick={() =>
          mutation.mutate({ id, title: `${todo?.title} (обновлено!)` })
        }
      >
        Обновить
      </button>
    </div>
  );
};

export default TodoComponent;

Использование invalidateQueries

Если вы хотите просто сказать React Query: "Эй, эти данные устарели, обнови-ка их!", используйте invalidateQueries. Этот метод заставляет библиотеку повторно выполнить запрос для указанных ключей.

const queryClient = useQueryClient();

queryClient.invalidateQueries({ queryKey: ['todo', id] });

Использование refetchQueries

Метод refetchQueries похож на invalidateQueries, но в данном случае вы явно повторно запрашиваете данные (рефетчинг).

queryClient.refetchQueries({ queryKey: ['todo'] });

staleTime и cacheTime: тонкая настройка

staleTime и cacheTime — это два ключевых параметра, которые позволяют управлять временем жизни данных в кэше.

  • staleTime (в миллисекундах) определяет, как долго данные считаются "свежими". В течение этого времени React Query не будет повторно запрашивать их при повторном рендере компонента.
  • cacheTime (в миллисекундах) определяет, как долго данные остаются в памяти (даже после того, как компонент размонтирован). После истечения cacheTime данные удаляются из кэша.

Пример настройки:

const { data } = useQuery({
  queryKey: ['todo', id],
  queryFn: () => fetchTodo(id),
  staleTime: 1000 * 60, // 1 минута
  cacheTime: 1000 * 60 * 5, // 5 минут
});

Примеры использования в реальном мире

Сценарий 1: локальное обновление данных после мутации

Представьте список задач (To-Do) и случай, когда пользователь добавляет новую задачу. Вместо повторного запроса списка задач вы можете оптимистически обновить кэш, добавив данные новой задачи.

Сценарий 2: автоматическое обновление при фокусе на вкладке

С помощью параметра refetchOnWindowFocus вы можете настроить автоматическое обновление данных при возврате пользователя на вкладку браузера.

const { data } = useQuery({
  queryKey: ['todos'],
  queryFn: fetchTodos,
  refetchOnWindowFocus: true,
});

Сценарий 3: отложенное удаление данных

Если данные редко меняются, вы можете увеличить cacheTime, чтобы кэш оставался в памяти дольше, и избежать лишних запросов.

Типичные ошибки

Иногда управление кэшем может вызывать неожиданные проблемы. Например, если вы забыли вызвать invalidateQueries после выполнения мутации, интерфейс пользователя может остаться с устаревшими данными. Либо, наоборот, высокие значения staleTime могут привести к тому, что новые данные с сервера останутся невидимыми для пользователя.

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