← Назад к вопросам

Как работает инвалидация в RTK Query?

2.0 Middle🔥 191 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как работает инвалидация в RTK Query

RTK Query - это мощная библиотека для управления серверным состоянием, встроенная в Redux Toolkit. Одна из ее ключевых фич - система инвалидации кэша, которая автоматически синхронизирует данные между клиентом и сервером.

Концепция инвалидации

Инвалидация означает: "отметить данные как устаревшие, нужно перезагрузить с сервера". RTK Query автоматически управляет этим процессом, перезагружая данные когда они помечены как невалидные.

1. Основной механизм - теги (tags)

Теги связывают запросы с мутациями. Когда мутация завершается, все запросы с соответствующими тегами инвалидируются:

// Определение API с тегами
const api = createApi({
  reducerPath: "api",
  baseQuery: fetchBaseQuery({ baseUrl: "/api/v1" }),
  tagTypes: ["Questions", "Comments", "User"],
  endpoints: (builder) => ({
    // Запрос с тегом
    getQuestions: builder.query({
      query: () => "/questions",
      providesTags: ["Questions"]  // Этот запрос "предоставляет" тег
    }),
    
    // Запрос с конкретным ID тега
    getQuestion: builder.query({
      query: (id) => `/questions/${id}`,
      providesTags: (result, error, id) => [
        { type: "Questions", id }  // Инвалидируется только этот ID
      ]
    }),
    
    // Мутация, инвалидирующая теги
    addQuestion: builder.mutation({
      query: (newQuestion) => ({
        url: "/questions",
        method: "POST",
        body: newQuestion
      }),
      invalidatesTags: ["Questions"]  // Инвалидирует все Questions запросы
    }),
    
    // Мутация с частичной инвалидацией
    editQuestion: builder.mutation({
      query: ({ id, ...body }) => ({
        url: `/questions/${id}`,
        method: "PATCH",
        body
      }),
      invalidatesTags: (result, error, { id }) => [
        { type: "Questions", id },  // Конкретный вопрос
        "Questions"                  // Все вопросы
      ]
    })
  })
});

2. Типы инвалидации

Инвалидация "по типу" (invalidatesTags: ["Questions"])

Инвалидирует ВСЕ запросы с этим типом тега:

addComment: builder.mutation({
  query: (comment) => ({
    url: "/comments",
    method: "POST",
    body: comment
  }),
  invalidatesTags: ["Comments"]  // Перезагрузит ВСЕ комментарии
})

Инвалидация "по ID" (invalidatesTags: [{ type: "Questions", id }])

Инвалидирует только запросы с конкретным ID:

updateComment: builder.mutation({
  query: ({ id, text }) => ({
    url: `/comments/${id}`,
    method: "PATCH",
    body: { text }
  }),
  invalidatesTags: (result, error, { id }) => [
    { type: "Comments", id }  // Только этот комментарий
  ]
})

3. Optimistic Updates (оптимистичные обновления)

Показать пользователю изменения до получения подтверждения с сервера:

const api = createApi({
  baseQuery: fetchBaseQuery({ baseUrl: "/api/v1" }),
  tagTypes: ["Questions", "Comments"],
  endpoints: (builder) => ({
    likeQuestion: builder.mutation({
      query: (questionId) => ({
        url: `/questions/${questionId}/like`,
        method: "POST"
      }),
      async onQueryStarted(questionId, { dispatch, queryFulfilled }) {
        // Оптимистично обновляем кэш
        const patchResult = dispatch(
          api.util.updateQueryData("getQuestion", questionId, (draft) => {
            draft.likesCount += 1;
            draft.isLiked = true;
          })
        );
        
        try {
          await queryFulfilled;
        } catch (error) {
          // Откатываем изменения при ошибке
          patchResult.undo();
          console.error("Ошибка при лайке:", error);
        }
      }
    })
  })
});

4. Практический пример в React компоненте

function QuestionEditor({ questionId }) {
  const { data: question, isLoading } = api.useGetQuestionQuery(questionId);
  const [editQuestion] = api.useEditQuestionMutation();
  
  const handleSave = async (title, content) => {
    try {
      // Мутация автоматически инвалидирует теги
      await editQuestion({
        id: questionId,
        title,
        content
      }).unwrap();
      
      // Кэш автоматически обновлен благодаря invalidatesTags
      // getQuestion запрос будет перезагружен
    } catch (error) {
      console.error("Ошибка сохранения:", error);
    }
  };
  
  if (isLoading) return <Skeleton />;
  
  return (
    <QuestionForm
      initialData={question}
      onSubmit={handleSave}
    />
  );
}

5. Комбинирование provides и invalidates тегов

const api = createApi({
  endpoints: (builder) => ({
    // Запрос предоставляет список и отдельные вопросы
    getQuestions: builder.query({
      query: () => "/questions",
      providesTags: (result) =>
        result
          ? [
              ...result.map(({ id }) => ({ type: "Questions", id })),
              { type: "Questions", id: "LIST" }
            ]
          : [{ type: "Questions", id: "LIST" }]
    }),
    
    // Мутация инвалидирует список
    addQuestion: builder.mutation({
      query: (newQuestion) => ({
        url: "/questions",
        method: "POST",
        body: newQuestion
      }),
      invalidatesTags: [{ type: "Questions", id: "LIST" }]
    })
  })
});

6. Управление инвалидацией вручную

Иногда нужна большая гибкость:

const [triggerRefresh] = api.useLazyGetQuestionsQuery();

function RefreshButton() {
  return (
    <button onClick={() => triggerRefresh()}>
      Обновить вопросы
    </button>
  );
}

// Или использовать утилиты RTK Query
const dispatch = useDispatch();

function ForceRefresh() {
  const handleClick = () => {
    dispatch(api.util.invalidateTags(["Questions"]));
  };
  
  return <button onClick={handleClick}>Форс обновление</button>;
}

Порядок выполнения инвалидации

  1. Мутация отправляется на сервер
  2. При успехе - находятся все запросы с invalidatesTags
  3. Эти запросы помечаются как невалидные
  4. Если компонент подписан на эти запросы - они перезагружаются

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

Как работает инвалидация в RTK Query? | PrepBro