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

使用Promise的useEffect正确清理方法,解决组件卸载更新状态警告

解决方案

你可以通过以下两种方式实现清理逻辑,避免该警告:

方案1:挂载状态标志位(快速实现)

在useEffect内部声明一个标志位记录组件是否仍处于挂载状态,所有状态更新操作执行前先校验该标志位:

useEffect(() => {
  // 标记组件是否挂载
  let isMounted = true;

  const fetchAllData = async () => {
    const resourceOne = new Promise((resolve) => {
      // 拉取资源1的逻辑
      fetch('/api/resource1')
        .then(res => res.json())
        .then(data => {
          // 仅挂载状态下更新状态
          if (isMounted) {
            // 这里更新对应state
          }
          resolve();
        })
    })
    const resourceTwo = new Promise((resolve) => {
      // 拉取资源2的逻辑
      fetch('/api/resource2')
        .then(res => res.json())
        .then(data => {
          if (isMounted) {
            // 这里更新对应state
          }
          resolve();
        })
    })
    const resourceThree = new Promise((resolve) => {
      // 拉取资源3的逻辑
      fetch('/api/resource3')
        .then(res => res.json())
        .then(data => {
          if (isMounted) {
            // 这里更新对应state
          }
          resolve();
        })
    })

    await Promise.all([resourceOne, resourceTwo, resourceThree])
    .then(() => {
      if (isMounted) {
        // 全部拉取完成后更新状态
      }
    })
  }

  fetchAllData();

  // 清理函数,组件卸载时修改标志位
  return () => {
    isMounted = false;
  }
},[])

这个方案实现简单,能快速解决警告问题,但缺点是不会终止实际的网络请求,仅会跳过卸载后的状态更新操作。

方案2:使用AbortController终止请求(更推荐)

如果使用的是fetch、axios等支持中断请求的请求库,可以用AbortController在组件卸载时直接取消未完成的请求,从根源避免后续的状态更新逻辑执行,还能节省不必要的网络资源消耗:

useEffect(() => {
  // 声明中断控制器
  const controller = new AbortController();
  const signal = controller.signal;

  const fetchAllData = async () => {
    try {
      const resourceOne = new Promise((resolve) => {
        // 绑定signal到请求中
        fetch('/api/resource1', { signal })
          .then(res => res.json())
          .then(data => {
            // 此处不需要额外判断,请求被中断会直接进入catch
            // 更新对应state
            resolve();
          })
      })
      const resourceTwo = new Promise((resolve) => {
        fetch('/api/resource2', { signal })
          .then(res => res.json())
          .then(data => {
            // 更新对应state
            resolve();
          })
      })
      const resourceThree = new Promise((resolve) => {
        fetch('/api/resource3', { signal })
          .then(res => res.json())
          .then(data => {
            // 更新对应state
            resolve();
          })
      })

      await Promise.all([resourceOne, resourceTwo, resourceThree])
      .then(() => {
        // 全部拉取完成后更新状态
      })
    } catch (err) {
      // 忽略请求中断的错误
      if (err.name !== 'AbortError') {
        console.error('请求出错:', err);
      }
    }
  }

  fetchAllData();

  // 清理函数,组件卸载时中断所有未完成的请求
  return () => {
    controller.abort();
  }
},[])

注:如果使用axios等其他请求库,对应中断请求的API可能略有不同,参考对应库的文档绑定取消信号即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.10 20:39:02