Реагировать на запрос

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

Когда дело доходит до запросов на изменение (таких как POST, PUT, PATCH и DELETE) в React Query, мы используем хук useMutation.

Проблемы с двойным запросом

Одной из основных проблем, которую часто пытаются решить разработчики интерфейса, является проблема запросов на двойную мутацию. (например, когда пользователь спамит кнопку отправки). Чтобы решить эту проблему, мы обычно добавляем к этим процессам логику устранения отказов.

Недавно я попытался глобально отменить дребезг функции mutate из хука useMutation, но, несмотря на несколько подходов, я не смог добиться желаемого результата. На мой взгляд, если бы это был осуществимый вариант, он, вероятно, был бы включен в react-query по умолчанию.

Решение

В качестве альтернативы я попытался реализовать решение, которое игнорировало бы новые запросы на мутацию, пока другой запрос на мутацию все еще ожидает обработки. Я создал новый хук под названием useSyncMutation (сокращение от синхронной мутации), который обернул хук useMutation и добавил следующую логику: если выполняется запрос и делается новый запрос для выполнения той же мутации, новый запрос игнорируется. Это оказалось относительно простой задачей.

Код:

import {useMutation} from 'react-query';

const useSyncMutation = (mutationFn, options) => {
  const mutationResults = useMutation(mutationFn, options);

  return {
    ...mutationResults,
    mutate: (...params) => {
      if (!mutationResults.isLoading) {
        mutationResults.mutate(...params);
      }
    }
  };
};

export default useSyncMutation;

Если вы используете машинописный текст:

import {UseMutationResult, useMutation, UseMutationOptions, MutationFunction} from 'react-query';

const useSyncMutation = <TData = unknown, TError = unknown, TVariables = void, TContext = unknown>(
  mutationFn: MutationFunction<TData, TVariables>,
  options?: Omit<UseMutationOptions<TData, TError, TVariables, TContext>, 'mutationKey'>
): UseMutationResult<TData, TError, TVariables, TContext> => {
  const mutationResults = useMutation(mutationFn, options);

  return {
    ...mutationResults,
    mutate: (...params: [TVariables]) => {
      if (!mutationResults.isLoading) {
        mutationResults.mutate(...params);
      }
    }
  };
};

export default useSyncMutation;

Сигнатура хука useSyncMutation такая же, как у хука useMutation, поэтому вы можете просто заменить useMutation на useSyncMutation, и весь ваш код продолжит работать, как и ожидалось, с дополнительными преимуществами новой функциональности.

Я надеюсь, что вы нашли это решение полезным. Пожалуйста, дайте мне знать в комментариях, если у вас есть какие-либо мысли или отзывы :)