Как использовать одну и ту же функцию запроса RTK несколько раз с разными параметрами в одном и том же компоненте?

В этой ситуации я пытаюсь использовать RTK-запрос с разными параметрами:
У меня есть корзина с несколькими товарами, каждый товар имеет счетчик для контроля количества купленного товара, поэтому я могу добавлять или удалять (увеличивать или уменьшать количество).
проблема:
хотя все счетчики имеют одинаковое определение запроса RTK, они используют триггер мутации и свойство isLoading, поэтому при нажатии на одну кнопку свойство isLoading переключается на true и отображает счетчики на всех других кнопках счетчиков.

Код компонента корзины:

const Cart = () => {
  const {
    isLoading,
    isSuccess,
    data: cart,
  } = useGetCartQuery({ userId: userData.id });
  const [addItem, { isLoading: isAddUpdating }] = useAddCartMutation();
  const [removeItem, { isLoading: isRemoveUpdating }] = useRemoveCartMutation();

  const handleAddBtn = (item: cartItemType) => {
    if (item.product.availability > item.quantity) {
      addItem({
        userId: userData.id as string,
        productId: item.product.id as string,
        quantity: 1,
      });
    } else {
      throw new Error("can't add more than items in stack");
    }
  };

  const handleRemoveBtn = (item: cartItemType, count) => {
    console.info(item, count);
    if (item.quantity >= count) {
      removeItem({
        userId: userData.id as string,
        productId: item.product.id as string,
        count: count,
      });
    }
  };
  return (
    <div>
      <QCounter
        availability = {item.product.availability}
        count = {item.quantity}
        handleAddBtn = {() => handleAddBtn(item)}
        handleRemoveBtn = {() => handleRemoveBtn(item, 1)}
        AddBtnLoading = {isAddUpdating}
        RemoveBtnLoading = {isRemoveUpdating}
        height = "36px"
        width = "36px"
      />
    </div>
  );
};

Код QCounter:

const QCounter = ({
  availability,
  count,
  handleAddBtn,
  handleRemoveBtn,
  AddBtnLoading,
  RemoveBtnLoading,
  height,
  width,
}) => {
  return (
    <div>
      <button
        onClick = {handleRemoveBtn}
        disabled = {count == 1 || RemoveBtnLoading}
      >
        {!RemoveBtnLoading ? (
          "-"
        ) : (
          <FaSpinner className = "animate-spin text-secondary" />
        )}
      </button>
      <div>
        <h3>{count}</h3>
      </div>

      <button
        onClick = {handleAddBtn}
        disabled = {count == availability || AddBtnLoading}
      >
        {!AddBtnLoading ? (
          "+"
        ) : (
          <FaSpinner className = "animate-spin text-secondary" />
        )}
      </button>
    </div>
  );
};

решения, которые я пробовал:
1- определить функцию запроса RTK для каждого элемента с помощью функции карты
я попытался определить их взамен с помощью функции карты, подобной этой

{cart.items.map((item: cartItemType) => {
                const [addItem, { isLoading: isAddUpdating }] = useAddCartMutation();
                const [removeItem, { isLoading: isRemoveUpdating }] = useRemoveCartMutation();

затем передайте addItem и isLoading каждому счетчику Qcounter, но я получил ошибку TS:
Хуки React должны вызываться в компоненте функции React или в пользовательской функции React Hook.

🤔 А знаете ли вы, что...
С React можно легко интегрировать с другими библиотеками и фреймворками.


1
60
1

Ответ:

Решено

Если я читаю и понимаю сообщение и код, вы, вероятно, сопоставляете cart данные, возвращаемые из useGetCartQuery в QCounter в первом фрагменте, и хотите, чтобы каждый QCounter имел свое собственное добавляющее/удаляющее «состояние» и индикатор.

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

Пример:

Корзина:

const Cart = () => {
  ...

  const {
    isLoading,
    isSuccess,
    data: cart,
  } = useGetCartQuery({ userId: userData.id });

  return (
    <div>
      {cart.items.map((item: cartItemType) => (
        <QCounter
          key = {item.product.id}
          item = {item}
          userId = {userData.id}
          height = "36px"
          width = "36px"
        />
      ))}
    </div>
  );
};

QСчетчик:

interface QCounterProps {
  item: cartItemType;
  userId: string;
  height: string;
  width: string;
}
const QCounter = ({
  height,
  item,
  userId,
  width,
}: QCounterProps) => {
  const [
    addItem,
    { isLoading: isAddUpdating }
  ] = useAddCartMutation();
  const [
    removeItem,
    { isLoading: isRemoveUpdating }
  ] = useRemoveCartMutation();

  const handleAddBtn = () => {
    if (item.product.availability > item.quantity) {
      addItem({
        userId,
        productId: item.product.id as string,
        quantity: 1,
      });
    } else {
      throw new Error("can't add more than items in stack");
    }
  };

  const handleRemoveBtn = () => {
    if (item.quantity > 0) {
      removeItem({
        userId,
        productId: item.product.id as string,
        count: item.quantity,
      });
    }
  };

  return (
    <div>
      <button
        onClick = {handleRemoveBtn}
        disabled = {item.quantity === 1 || isRemoveUpdating}
      >
        {isRemoveUpdating
          ? <FaSpinner className = "animate-spin text-secondary" />
          : "-"
        }
      </button>

      <div>
        <h3>{item.quantity}</h3>
      </div>

      <button
        onClick = {handleAddBtn}
        disabled = {item.quantity === item.product.availability || isAddUpdating}
      >
        {isAddUpdating
          ? <FaSpinner className = "animate-spin text-secondary" />
          : "+"
        }
      </button>
    </div>
  );
};