为了账号安全,请及时绑定邮箱和手机立即绑定

React16.7 hooks之setTimeout引发的bug小记

标签:
AngularJS


React16.7 hooks之setTimeout引发的bug

前言

  周末尝试了一下React新的hooks功能,来封装一个组件,遇到一个bug,所以记录一下过程!

报错如下:

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 Notification

大概意思是组件已经卸载了,但在卸载之后还执行了一个对组件更新的操作,这是一个无效的操作,但它表示应用程序中存在内存泄漏。要修复,请取消useEffect cleanup function.in Notification 中的所有订阅和异步任务

Can't perform a React state update on an unmounted component.,Read the Motivation to learn why we’re introducing Hooks to React

组件核心代码如下:

function Notification(props){

  var timer = null;

  const [visible, setVisible] = useState(false);

  let {title,description,duration,theme,onClose,}= props;

  let leave = (source='') => {

    clearTimeout(timer);

    setVisible(false);

    console.log("注意这里是 leave方法里,timer的id:"+timer,"事件的来源:",source);

    console.log("leave result:",timer);

    onClose&&onClose();

  }

  let enter = () => {

    setVisible(true);

    if( duration > 0 ){

      let timer = setTimeout(() => {

        console.log(`auto carried out`,timer) //timer Number Id 

        leave(`Time to`);

      }, duration*1000);

      console.log(`enter方法里,timer的id:`,timer) //timer Number Id 

    }

  }

  useEffect(()=>{

    enter();

  },[])

  return (

    <div className={`${prefixCls}-notice`} style={{display:`${visible?'':'none'}`}}>

      {!!theme&&<p className={`${prefixCls}-notice-icon`}><Svg iconId={`svg-${theme}`} /></p>}

      <div className={`${prefixCls}-notice-content`}>

      ……//首席填坑官∙苏南的专栏 交流:912594095、公众号:honeyBadger8

      </div>

      <p className={`${prefixCls}-notice-colse`} title="关闭" onClick={()=>leave("手动点击的关闭")}><Svg/></p>

    </div>

  );

};

简单分析:

首先useEffect方法,是react新增的,它是componentDidMount,componentDidUpdate、componentWillUnmount三个生命周期的合集,

也就是之前的写法,上面三生命周期里会执行到的操作,useEffect都会去做;

enter、leave方法

很好理解,进场、出场两函数,

进场:加了个定时器,在N秒后执行出场即leave方法,这个逻辑是正常的,

问题就出在手动执行leave,也就是事件上,

问题原因:

其实就是在点击事件的时候,没有获取到 timer的id,导致了定时器没有清除掉;

!!看图说话:

React v16.7 

解决思路:

当然是看官方文档,hooks对我来说也是个新玩意,不会~

1、useEffect方法里return 一个方法,它是可以在组件卸载时执行的,

2、清除定时器它有自己的方式,const intervalRef = useRef();指定赋值后能同步更新,之前的timer手动执行没有拿到timer所以没有清除掉;

React v16.7 

参考链接:

中文,英文的没有找到

文档英文的也补一下吧

react github也有人提到这个问题,学习了

完美解决:

请取消useEffect cleanup function.in Notification 中的所有订阅和异步任务

function Notification(props){

  var timer = null;

  const [visible, setVisible] = useState(false);

  let {title,description,duration,theme,onClose,}= props;

  const intervalRef = useRef(null);

  let leave = (source='') => {

    clearTimeout(intervalRef.current);

    setVisible(false);

    console.log("leave result:",source,intervalRef);

    onClose&&onClose();

  }

  let enter = () => {

    setVisible(true);

    if( duration > 0 ){

      let id = setTimeout(() => {

        console.log(`auto carried out`,intervalRef) //timer Number Id 

        leave(`Time to`);

      }, duration*1000);//首席填坑官∙苏南的专栏 交流:912594095、公众号:honeyBadger8

      intervalRef.current = id;

    }

  }

  useEffect(()=>{

    enter();

    return ()=>clearTimeout(intervalRef.current);

  },[])

  return (

    <div className={`${prefixCls}-notice`} style={{display:`${visible?'':'none'}`}}>

      {!!theme&&<p className={`${prefixCls}-notice-icon`}><Svg iconId={`svg-${theme}`} /></p>}

      <div className={`${prefixCls}-notice-content`}>

        ……//首席填坑官∙苏南的专栏 交流:912594095、公众号:honeyBadger8

      </div>

      <p className={`${prefixCls}-notice-colse`} title="关闭" onClick={()=>leave("手动点击的关闭")}><Svg/></p>

    </div>

  );

};

宝剑锋从磨砺出,梅花香自苦寒来,做有温度的攻城狮!,公众号:honeyBadger8


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消