React 组件销毁时清除订阅、定时器以及清理异步操作和取消请求等资源

该文介绍了React中遇到的警告——无法对已卸载组件执行状态更新,这是内存泄漏的迹象。解决方法是在useEffect中提供清理函数,确保在组件卸载时取消订阅和清除定时器,以防止不必要的状态更新和资源浪费。示例代码展示了如何在订阅和定时器场景下正确清理。
摘要由CSDN通过智能技术生成

问题:

Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
in GlobalHeaderRight (at app.tsx:173)
in div (created by GlobalHeader)
in GlobalHeader (created by HeaderView)
in header (created by Basic)
in Basic (created by Header)
in Header (created by HeaderView)
in HeaderView (created by BasicLayout)
in div (created by BasicLayout)
in section (created by BasicLayout)
in BasicLayout (created by Layout)
in Layout (created by BasicLayout)
in div (created by BasicLayout)

翻译翻译:

警告:无法对未安装的组件执行 React 状态更新。 这是一个空操作,但它表明您的应用程序中存在内存泄漏。 要解决此问题,请在 useEffect 清理函数中取消所有订阅和异步任务。

解决办法:清除 effect

通常,组件卸载时需要清除 effect 创建的诸如订阅或计时器 ID 等资源。要实现这一点,useEffect 函数需返回一个清除函数。
以下是一个创建订阅的例子:

useEffect(() => {
  const subscription = props.source.subscribe();
  return () => {
    // 清除订阅
    subscription.unsubscribe();
  };
});

以下是一个定时器例子:

  const [time, setTime] = useState('')
  let num = 0;
  let timer: any;
  const updateTime = () => {
    timer = clearTimeout(timer);
    num += 1;
    if (num == 10) {
      num = 0;
      setTime(moment().format('YYYY-MM-DD HH:mm:ss'));
    }
    timer = setTimeout(() => {
      updateTime()
    }, 100);
  }
  
  useEffect(() => {
    updateTime()
    return () => {
      // 清除定时器
      clearTimeout(timer)
    };

为防止内存泄漏,清除函数会在组件卸载前执行。另外,如果组件多次渲染(通常如此),则在执行下一个 effect 之前,上一个 effect 就已被清除。在上述示例中,意味着组件的每一次更新都会创建新的订阅。


react 组件销毁时 清理异步操作和取消请求

在componetWillMount 中访问了接口返回数据后,调用了setState,访问的时候按了后退,导致还没收到响应就销毁了组件 ,但是fetch请求没被结束掉,之后收到响应就调用了setState(),发出如上所示警告。

原因:React中,因为异步操作的关系,组件销毁后调用了setState();

解决办法:(加个 return)

使用 class 组件解决办法:

componentWillUnmount(){
        // 卸载异步操作设置状态
        this.setState = (state, callback) => {
            return;
        }
    }

使用函数组件解决办法:

一个简单的办法是标记一下组件有没有被卸载,可以利用 useEffect的返回值。

// 省略组件其他内容,只列出 diff
useEffect( => {
  let isUnmounted = false;
  (async => {
    const res = await fetch(SOME_API);
    const data = await res.json;
    if (!isUnmounted) {
      setValue(data.value);
      setLoading(false);
    }
  });
  return => {
  isUnmounted = true;
  }
}, []);

参考资料:https://www.cnblogs.com/art-poet/p/13276874.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gxhlh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值