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

React调用API更新state时报无法对已卸载组件执行状态更新错误如何解决

问题原因

你遇到的警告触发逻辑是:页面组件已经卸载(比如用户跳转到其他页面)时,之前发起的异步接口请求还在执行,请求返回后仍然尝试给已卸载的组件更新状态,存在内存泄漏风险。

解决方案

1. 先修正语法错误

你现有代码中第一个useEffect缺少闭合括号,先补全:

useEffect(() => {
  fetchUserData(auth.apiToken).then((data) => {
    console.log(data);
    setUser(data);
  }) // 原代码漏了这行的闭合
}, [auth.apiToken]);

2. 给所有异步请求的useEffect加挂载状态判断

在每个发请求的useEffect里加一个标记变量,跟踪组件是否还挂载,只有组件未卸载时才更新状态:

// 获取用户信息的useEffect修改后
useEffect(() => {
  let isMounted = true;
  fetchUserData(auth.apiToken).then((data) => {
    if (isMounted) {
      console.log(data);
      setUser(data);
    }
  });
  // 组件卸载时更新标记
  return () => {
    isMounted = false;
  };
}, [auth.apiToken]);

// 获取项目列表的useEffect修改后
useEffect(() => {
  let isMounted = true;
  fetchUserProjects(auth.apiToken).then((data) => {
    if (isMounted) {
      console.log(data);
      setIdKitData(data);
    }
  });
  return () => {
    isMounted = false;
  };
}, [auth.apiToken]);

// 获取Map数据的useEffect修改后
// 注意:这里要把idKitData加入依赖数组,还要加空值判断避免初始状态报错
useEffect(() => {
  let isMounted = true;
  // 只有idKitData有值且存在projects数组时才发请求
  if (idKitData?.projects?.length) {
    fetchMapById(auth.apiToken, idKitData.projects[1].lab.id).then((data) => {
      if (isMounted) {
        console.log(data);
        setKitData(data);
      }
    });
  }
  return () => {
    isMounted = false;
  };
}, [auth.apiToken, idKitData]);

// 获取点位数据的useEffect修改后
useEffect(() => {
  let isMounted = true;
  fetchEncounterByMaps(auth.apiToken).then((data) => {
    if (isMounted) {
      console.log(data);
      setMapsData(data);
    }
  });
  return () => {
    isMounted = false;
  };
}, [auth.apiToken]);

3. 可选:更严谨的方案,主动取消未完成请求

如果你的api是基于fetch封装的,可以用AbortController在组件卸载时直接取消未完成的请求,从根源避免后续逻辑执行:
首先调整请求函数,接收signal参数:

export const fetchMapById = async (token, projectId, signal) => {
  const {data} = await api(`/projects/v1/project/${projectId}`,
  {
    method: "GET", 
    headers: {
      Authorization: `Bearer ${token}`,
    },
    signal // 传入取消信号
  })
 return data;
};

然后修改对应useEffect:

useEffect(() => {
  const controller = new AbortController();
  if (idKitData?.projects?.length) {
    fetchMapById(auth.apiToken, idKitData.projects[1].lab.id, controller.signal)
      .then(data => setKitData(data))
      .catch(err => {
        // 忽略请求取消的报错
        if (err.name !== 'AbortError') console.error(err);
      })
  }
  // 组件卸载时取消请求
  return () => controller.abort();
}, [auth.apiToken, idKitData])

4. 额外逻辑优化

因为fetchMapById依赖fetchUserProjects的返回结果,你可以把两个请求合并到同一个useEffect中,减少不必要的重渲染:

useEffect(() => {
  let isMounted = true;
  const fetchAllData = async () => {
    // 先拿项目列表
    const projectData = await fetchUserProjects(auth.apiToken);
    if (isMounted) setIdKitData(projectData);
    // 再拿对应map数据
    if (projectData?.projects?.length) {
      const mapData = await fetchMapById(auth.apiToken, projectData.projects[1].lab.id);
      if (isMounted) setKitData(mapData);
    }
  }
  fetchAllData();
  return () => {
    isMounted = false;
  }
}, [auth.apiToken])

修改后即可解决警告,同时保证接口数据正常返回供后续逻辑使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 14:39:05