React16.7 hooks 之 setTimeout 引发的 bug

2018-12-13 15:19:30 +08:00
 suSouth

前言

周末尝试了一下 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 中的所有订阅和异步任务

组件核心代码如下:


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>
  );
};

简单分析:

enter、leave 方法
问题原因:

解决思路:

参考链接:

中文,英文的没有找到 文档英文的也补一下吧 react github 也有人提到这个问题,学习了

完美解决:


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>
  );
};

热门推荐

作者:苏南 - 首席填坑官 链接: https://blog.csdn.net/weixin_43254766/article/details/83758660 交流:912594095、公众号:honeyBadger8 本文原创,著作权归作者所有。商业转载请联系@IT·平头哥联盟获得授权,非商业转载请注明原链接及出处。

1158 次点击
所在节点    分享发现
0 条回复

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/517243

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX