资讯专栏INFORMATION COLUMN

一个removeEventListener引发的思考

jeyhan / 2527人阅读

摘要:而为对象时,可用选项如下之所以第三个参数有两种形态,是在旧版本中只存在一个布尔值,即属性但随着时间推移以及发展的需要,需要支持设置更多的特性设置,所以有了选项这个对象传参,又为了兼容以前的老程序,所以对两者进行了兼容。

起因

最近在看以前的代码时,发现年初在熟悉react hooks新特性时写下了这样一段代码:

let i = 0;
function Test(props) {
  const { loading, error, startFetch } = props;
  useEffect(() => {
    const $btn = document.querySelector(".btn"); // .info-con 存在于外层的dom中
    $btn.addEventListener("click", () => {
      const action =`action data${i++}`;
      console.log("resbtn", action);
    }, false);
    return $btn.removeEventListener("click", () => {});
  });
  if (error) {
    return 
{error.msg}
; } return (
{loading &&

loading

}

finished

Saga模拟测试

); }

我用了addEventListener和removeEventListener来尝试useEffect的挂载和清除功能,细心的你,发现这段代码有几个错误呢?
自我观察,自认为是有如下几个的:

清除函数使用方式错误,应该返回的是一个函数,like:() => { $btn.removeEventListener("click", () => {}); },而我这里是一个语句;

removeEventListener使用语法错误;

useEffect未使用第二个参数,导致addEventListener挂载会多次执行(可以优化)

第1个和第3个错误,是可以原谅的,当时自己对hooks还不熟悉。但第二个错误,是不可原谅的,这是需要检讨的。本文后面不会对useEffect做深入讲解,官方文档已经足够清楚,后面围绕removeEventListener来剖析。

认清removeEventListener

第二个错误,拆开看,又可分为两个方面:removeEventListener使用方式多余与语法错误。

使用方式多余:虽然$btn添加了click监听事件回调,但由于这个节点属于当前Test组件,所以组件销毁时,其相关节点的监听事件也会一并销毁,这个在自己刚接触前端时就做过这一方面的解析,所以这里的removeEventListener使用是多余的。但如果换成一个组件外的节点,比如我后面替换的.info-con节点,这是一直存在于Layout组件中的,使用removeEventListener是必要的。

语法错误:指使用removeEventListener,前面两个参数是必传的,事件类型(type:click),事件回调函数(listener: callback),由于使用addEventListener是为事件添加的一个队列(即同一个事件,可添加多个监听回调),所以事件回调函数(listener)是必传,且其引用与添加的事件监听回调函数指向相同。详细描述见官方文档

关于语法错误,官方文档中有这样一段描述:

由于我在添加监听时,使用的是箭头函数,所以删除时无法找到相同引用的监听事件,所以第一件事就是改变监听函数的写法。完善后,写法是下面这样的:

let i = 0;
function Test(props) {
  const { loading, error, startFetch } = props;
  useEffect(() => {
    const $btn = document.querySelector(".info-con");
    const eventAction = () => {
      const action =`action data${i++}`;
      console.log("resbtn:", action);
    };
    $btn.addEventListener("click", eventAction);
    return () => {
      $btn.removeEventListener("click", eventAction);
    };
  }, []);
  if (error) {
    return 
{error.msg}
; } return (
{loading &&

loading

}

finished

Saga模拟测试

); }

到此,看似已经结束了。但既然已经打开了,就深入的学习一下这个api吧,常用的前两个参数,我们都很熟悉,第三个参数写成布尔值也偶尔会有,但是否已足够了解呢?

第三个参数

addEventListener和removeEventListener传参是一样的,第三个可选参数都是一个对象或者一个布尔值:

target.addEventListener(type, listener[, options]);
target.addEventListener(type, listener[, useCapture]);
target.removeEventListener(type, listener[, options]);
target.removeEventListener(type, listener[, useCapture]);

当参数为布尔值时,意指useCapture,是否在捕获阶段触发监听函数。而为对象时,可用选项如下:

clipboard.png
之所以第三个参数有两种形态,是在旧版本中只存在一个布尔值,即useCapture属性;但随着时间推移以及发展的需要,需要支持设置更多的特性设置,所以有了options选项这个对象传参,又为了兼容以前的老程序,所以对两者进行了兼容。once和passive属性非常有趣,但我还没想到合适的使用它们的场景。查看官方文档,发现里面确实有好多以前没有关注到的东西,值得细细品味。
其实在js很多api中,我们都只用了一些常用的用法,而忽略了一些存在且也很适用的不常用传参,比如下面这些:

setTimout(callback, time, ...params): 这个有多有用呢,有一道网红面试题,关于闭包的,就可以利用这个参数来解决,在详解网红前端经典面试题:setTimeout与循环闭包提到过

    function test(){
         for (var i=0; i<5; i  ) {
            setTimeout( function timer() {
                console.log(new Date(),i);
            }, 1000);
        }
        console.log("end",new Date(),i);
    }

bind(thisArg, ...params): 为函数预先传参,在react中用的比较多;

replace(reg, str | function): replace第二参数也可以为一个函数,用于自定义替换

split(reg, length): split其实也是有第二个参数的,用以指定返回数组的长度不超过指定大小;

暂时想不起来了...

思考

这一次关于对removeEventListener的使用错误,让我不得不意识到,对于自己下一步技术提升的着重点还是该多关注基础,不要学的太宽泛,而成为泛而不精的人,最后一无是处。最近这一年确实太痴迷(yilai)于框架(React),基础关注的太少。框架与基础,框架层出不穷,但基础只是持续在演进。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/106381.html

相关文章

  • Vue一个案例引发动态组件与全局事件绑定总结

    摘要:我们需要的最好效果肯定是当前的全局事件就在当前的组件下产生作用,当我们切换到其他组件时,事件自动删除,于是我可能想到的就是利用钩子函数去删除这个全局事件。 最近在自学 Vue 也了解了一些基本用法,也记录了一些笔记有兴趣的朋友可以去查看我的其他文章,技术这东西真的不能光靠看,看是没有的,你必须要动手实践,只有在实战项目中才能发现问题,才能发现我们没有掌握的知识点,然后发现问题解决问题,...

    MycLambert 评论0 收藏0
  • 「读懂源码系列1」还在恐惧读源码?看完这篇就不怕了

    摘要:源码真的这么可怕吗从以上的事例中可以看出,其实并没有。对于源码的恐惧,让我们渐渐思维固化,自己告诉自己不要去碰源码,时间长了就遗忘了还有这样一条路可走。 一个小需求 事情的起因,是昨天有一个新的需求被提出。 需求是要实现,让我们自己定制的弹出层,具备按下 ESC 也能退出的功能。我把任务交给了同组的小伙伴S去实现。(这个项目用到了vue技术栈,以及饿了么的UI框架。) 我开完会回来,发...

    XGBCCC 评论0 收藏0
  • DOM事件总结(一)

    摘要:三级事件处理程序级事件定义了两个方法,分别用于处理指定和删除事件处理程序的操作和,他们都接收三个参数要处理的事件名作为事件处理程序的函数一个布尔值。布尔值如果是表示在捕获阶段调用事件处理程序,如果是表示在冒泡阶段调用事件处理程序。 前言:撸完CSS-DOM紧接着来撸DOM事件,事件总结完成后我要开始总结动画,然后用纯JS实现一个轮播图,前路漫漫,还有各种框架等着我~~~本篇主要内容有:...

    hedge_hog 评论0 收藏0
  • 从一次重写原生方法遇到坑,总结一下Web中事件系统

    摘要:问题初探索删掉那一点重写的代码后,表现符合预期了。每一次都重新造一个虚拟的,然后监听其自定义事件,并且立即触发这个自定义事件。真的不要随便重写原生方法。。。于是,我全面总结一下了中的事件系统,也算是对基础的巩固。 写在前面 前段时间,我写过一篇文章前端开发中的Error以及异常捕获。 在文章中,我提到了这个问题: showImg(https://segmentfault.com/img...

    oysun 评论0 收藏0
  • JavaScript中一个运算符优先级问题引发思考

    摘要:中一个运算符优先级问题引发的思考题目假设已经声明可定义为任何值。分析因为我们忽略了运算符的优先级。要知道,加号优先级高于三目运算,低于括号。为值,在里的判断就是值。 JavaScript中一个运算符优先级问题引发的思考 题目 假设 val 已经声明,可定义为任何值。则下面js代码有可能输出的结果为: console.log(Value is + (val != 0) ? define...

    zengdongbao 评论0 收藏0

发表评论

0条评论

jeyhan

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<