You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

RTK Query请求报错时react-toastify重复弹出Toast的解决方法

问题:RTK Query请求错误时Toast重复弹出的解决方法

使用RTK Query获取数据时,请求出错后通过react-toastify弹出的提示会重复出现,控制台显示错误判断的代码段多次执行,如何阻止Toast重复弹出?

相关代码:

import FoodBox from "../components/FoodBox";

import styled from "styled-components";
import { useFetchFoodsQuery } from "../store";
import { useSelector } from "react-redux";
import Skeleton from "./Skeleton";
import { toast } from "react-toastify";

const Foods = styled.div`
  overflow-y: auto;
  overflow-x: hidden;
  height: 370px;
  padding: 0 30px;
`;

function FoodList({ shopId }) {
  let { data: foods, error, isFetching } = useFetchFoodsQuery(shopId);
  const user = useSelector((state) => state.user.currentUser);
  let content;
  if (isFetching) {
    content = (
      <Foods>
        <Skeleton w="22.5rem" h="3.5rem" times={5} />
      </Foods>
    );
  } else if (error) {
    toast('Error');
    return <div>Error in loading food</div>;
  } else {
    if (!user) {
      foods = foods?.filter((food) => food.isVisible);
    }
    content = (
      <Foods>
        {foods?.map((food) => (
          <FoodBox key={food?._id} food={food} />
        ))}
      </Foods>
    );
  }

  return content;
}

export default FoodList;

核心原因

组件因shopId变化、user状态更新等原因重新渲染时,只要error状态存在,toast('Error')就会重复执行,导致多次弹出提示。

解决办法

方法1:用useEffect监听error变化,仅首次触发Toast

利用React的useEffect钩子,仅在error从无到有发生变化时调用toast,避免重复触发:

import FoodBox from "../components/FoodBox";
import styled from "styled-components";
import { useFetchFoodsQuery } from "../store";
import { useSelector } from "react-redux";
import Skeleton from "./Skeleton";
import { toast } from "react-toastify";
import { useEffect } from "react"; // 引入useEffect

const Foods = styled.div`
  overflow-y: auto;
  overflow-x: hidden;
  height: 370px;
  padding: 0 30px;
`;

function FoodList({ shopId }) {
  let { data: foods, error, isFetching } = useFetchFoodsQuery(shopId);
  const user = useSelector((state) => state.user.currentUser);
  let content;

  // 新增:仅在error状态变化时触发一次Toast
  useEffect(() => {
    if (error) {
      toast('Error');
    }
  }, [error]);

  if (isFetching) {
    content = (
      <Foods>
        <Skeleton w="22.5rem" h="3.5rem" times={5} />
      </Foods>
    );
  } else if (error) {
    return <div>Error in loading food</div>;
  } else {
    if (!user) {
      foods = foods?.filter((food) => food.isVisible);
    }
    content = (
      <Foods>
        {foods?.map((food) => (
          <FoodBox key={food?._id} food={food} />
        ))}
      </Foods>
    );
  }

  return content;
}

export default FoodList;

方法2:给Toast设置唯一ID,避免重复显示

react-toastify支持通过toastId指定唯一标识,相同ID的Toast不会重复弹出:

// 修改error分支的toast调用
else if (error) {
  toast('Error', { toastId: 'food-fetch-error' }); // 固定唯一ID
  return <div>Error in loading food</div>;
}

方法3:结合RTK Query的isError状态(可选)

RTK Query的查询钩子返回isError布尔值,可配合useEffect使用,逻辑更直观:

let { data: foods, error, isFetching, isError } = useFetchFoodsQuery(shopId);

// 配合useEffect触发Toast
useEffect(() => {
  if (isError) {
    toast('Error');
  }
}, [isError]);

注意事项

  • 优先选择方法1,能精准监听error变化,避免不必要的Toast触发;
  • 方法2适合简单场景,若需区分不同错误,需调整toastId;
  • 当shopId变化触发新请求时,新的错误应重新触发Toast,这属于合理行为,无需额外处理。

内容的提问来源于stack exchange,提问作者Het Patel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 22:03:35