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

React表单提交时useEffect重复触发API调用致400错误如何解决

核心问题原因

  1. ShowRoleApp组件的useEffect未将applicationRole加入依赖数组,组件每次挂载都会发起请求,且父组件表单提交触发的重渲染会导致组件重复挂载,进而多次调用接口。
  2. 未添加请求取消逻辑,未完成的请求在响应返回后仍会触发状态更新,进一步引发多余重渲染和重复请求。
  3. GetProfili中不必要的res.clone()调用可能导致响应解析异常,触发额外重渲染。

具体修改方案

1. 修正ShowRoleApp组件的useEffect逻辑

添加正确依赖、请求取消逻辑、组件卸载保护,避免重复请求:

const ShowRoleApp = ({ applicationRole }) => {
  const [profili, setProfili] = useState([]);
  const [isLoading, setIsLoading] = useState(false);

  useEffect(() => {
    // 没有选中值时直接清空状态返回
    if (!applicationRole) {
      setProfili([]);
      setIsLoading(false);
      return;
    }
    setIsLoading(true);
    // 声明abort控制器用于取消请求
    const abortController = new AbortController();
    let isMounted = true;

    async function init() {
      try {
        const res = await GetProfili(applicationRole, abortController.signal);
        // 组件未卸载才更新状态
        if (isMounted) {
          setProfili(res);
          setIsLoading(false);
        }
      } catch (err) {
        // 忽略请求取消的报错
        if (err.name !== 'AbortError' && isMounted) {
          console.log('err ', err);
          setIsLoading(false);
        }
      }
    }
    init();

    // 清理函数:组件卸载/依赖变化时取消请求,标记组件已卸载
    return () => {
      isMounted = false;
      abortController.abort();
    };
  // 把applicationRole加入依赖数组,只有值变化才重新执行effect
  }, [applicationRole]);

  if (!applicationRole) {
    return <div />;
  }

  return isLoading ? (
    <div className='d-flex justify-content-center'>
      <div className='spinner-border text-primary' role='status'>
        <span className='visually-hidden'></span>
      </div>
    </div>
  ) : (
    RenderProfili(profili, applicationRole)
  );
};

2. 优化GetProfili函数

移除多余clone调用,支持传入abort信号:

const GetProfili = async (appCod, signal) => {
  const chiamata = 'myApi' + appCod.toString();
  const res = await fetch(chiamata, { signal });
  // 直接调用json()即可,无需clone
  const result = await res.json();
  return result;
};

可选优化:添加请求防抖

如果下拉选择时需要避免快速切换选项触发多次请求,可添加防抖逻辑:

// 全局声明防抖函数
const debounce = (func, delay = 300) => {
  let timeoutId;
  return (...args) => {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => func.apply(this, args), delay);
  };
};

// ShowRoleApp内使用防抖后的请求函数
const fetchProfili = useCallback(debounce(async (appCod, signal) => {
  // 请求逻辑同上
}), []);

修改后只有当applicationRole的值发生变化时才会发起新请求,提交表单时的重渲染不会再触发重复调用,400错误也会随之解决。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 10:15:02