的起因最近在看之前的代码的时候,发现自己在年初熟悉reacthooks的新特性的时候写了这么一段代码:leti=0;functionTest(props){const{loading,error,startFetch}=props;useEffect(()=>{const$btn=document.querySelector('.btn');//.info-con存在于外层dom$btn.addEventListener('click',()=>{constaction=`动作数据${i++}`;console.log('resbtn',action);},false);return$btn.removeEventListener('click',()=>{});});如果(错误){返回
{error.msg}
;}return({loading&&finished获取数据Saga模拟测试
);}我使用了addEventListener和removeEventListener来尝试useEffect的挂载和清除功能.细心的你,你在这段代码中发现了多少错误?自我观察,我觉得有以下几点:clear函数的使用是错误的,应该返回一个函数,如:()=>{$btn.removeEventListener('点击',()=>{});},这是一个声明;removeEventListener使用语法错误;useEffect没有使用第二个参数,导致addEventListener被多次挂载(可以优化)第1、3个错误可以原谅。当时对hooks还不熟悉,但是第二个错误不可原谅,需要重温。本文不会对useEffect做深入的讲解。官方文档说的够清楚了,后面会围绕removeEventListener进行分析。认识到removeEventListener的第二个错误,在反汇编的时候可以分为两个方面:removeEventListener的冗余使用和语法错误。冗余用法:虽然$btn添加了点击监听事件回调,但是由于该节点属于当前Test组件,当该组件销毁时,其相关节点的监听事件也会被销毁。这是我刚开始接触前端时做的这方面的解析,所以这里使用removeEventListener是多余的。但是如果换成组件外的节点,比如我后面替换的.info-con节点,这个在Layout组件中一直存在,需要用到removeEventListener。语法错误:指的是使用removeEventListener,前两个参数必须传,事件类型(type:click),事件回调函数(listener:callback),由于使用addEventListener是为事件添加的队列(即同一个事件,可以添加多个监听回调),所以必须传递事件回调函数(listener),其引用与添加的事件监听回调函数相同。详细说明请参考官方文档。关于语法错误,官方文档中有描述:由于我在添加监听时使用了箭头函数,删除时找不到相同引用的监听事件,所以首先要做的是更改监听函数写作方式。完成后,写法如下:leti=0;functionTest(props){const{loading,error,startFetch}=props;useEffect(()=>{const$btn=document.querySelector('.info-con');consteventAction=()=>{constaction=`actiondata${i++}`;console.log('resbtn:',action);};$btn.addEventListener('click',eventAction);return()=>{$btn.removeEventListener('click',eventAction);};},[]);如果(错误){返回loading
}{error.msg}
;}return({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,是否在捕获阶段触发监听函数。当为对象时,可用选项如下:第三个参数之所以有两种形式,是因为旧版本只有一个布尔值,即useCapture属性;但是随着时间的推移和开发的需要,需要支持设置更多的特性设置,所以使用options选项来传递参数,同时为了兼容老程序,两者兼容。once和passive属性很有趣,但我还没有想到适合它们的用例。翻看官方文档,发现确实有很多之前没注意的地方,值得细细品味。其实在很多jsAPI中,我们只使用了一些常用的用法,而忽略了一些不常用的参数,这些参数是存在的,也是非常适用的,比如下面这样:setTimout(callback,ti??me,...params):这个有多大用处它?有个网红面试题关于闭包,用这个参数就可以解决。网红前端经典面试题详解:setTimeout和循环闭包中提到functiontest(){for(vari=0;i<5;i){setTimeout(functiontimer(){console.log(新日期(),i);},1000);}console.log('end',newDate(),i);}bind(thisArg,...params):函数的预传参数,在react中经常用到;replace(reg,str|function):replace的第二个参数也可以是自定义替换的函数split(reg,length):split其实还有第二个参数,用来指定返回数组的长度不超出指定尺寸;暂时想不起来了。。。想想这次removeEventListener的使用就觉得很不爽我没有意识到我下一步技术提升的重点应该是更加注重基础,不要学的太广,成为一个泛而不精的人,到头来还是一无是处。在过去的一年里,我对框架(React)过于痴迷(yilai),对基础知识的关注太少。框架和基础,框架层出不穷,但基础只是在进化。