最近在看之前的代碼時,發現年初在熟悉react hooks新特性時寫下了這樣一段代碼:javascript
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 <div>{error.msg}</div>; } return ( <div> {loading && <h3>loading</h3>} <h3 className="mt-10 mb-10">finished</h3> <button onClick={startFetch}>獲取數據</button> <h4 className="mt-10"><span className="btn">Saga模擬測試</span></h4> </div> ); }
我用了addEventListener和removeEventListener來嘗試useEffect的掛載和清除功能,細心的你,發現這段代碼有幾個錯誤呢?
自我觀察,自認爲是有以下幾個的:html
第1個和第3個錯誤,是能夠原諒的,當時本身對hooks還不熟悉。但第二個錯誤,是不可原諒的,這是須要反省的。本文後面不會對useEffect作深刻講解,官方文檔已經足夠清楚,後面圍繞removeEventListener來剖析。前端
第二個錯誤,拆開看,又可分爲兩個方面:removeEventListener使用方式多餘與語法錯誤。java
關於語法錯誤,官方文檔中有這樣一段描述: react
因爲我在添加監聽時,使用的是箭頭函數,因此刪除時沒法找到相同引用的監聽事件,因此第一件事就是改變監聽函數的寫法。完善後,寫法是下面這樣的:面試
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 <div>{error.msg}</div>; } return ( <div> {loading && <h3>loading</h3>} <h3 className="mt-10 mb-10">finished</h3> <button onClick={startFetch}>獲取數據</button> <h4 className="mt-10"><span className="btn">Saga模擬測試</span></h4> </div> ); }
到此,看似已經結束了。但既然已經打開了,就深刻的學習一下這個api吧,經常使用的前兩個參數,咱們都很熟悉,第三個參數寫成布爾值也偶爾會有,可是否已足夠了解呢?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屬性很是有趣,但我還沒想到合適的使用它們的場景。查看官方文檔,發現裏面確實有好多之前沒有關注到的東西,值得細細品味。
其實在js不少api中,咱們都只用了一些經常使用的用法,而忽略了一些存在且也很適用的不經常使用傳參,好比下面這些:框架
function test(){ for (var i=0; i<5; i ) { setTimeout( function timer() { console.log(new Date(),i); }, 1000); } console.log('end',new Date(),i); }
這一次關於對removeEventListener的使用錯誤,讓我不得不意識到,對於本身下一步技術提高的着重點仍是該多關注基礎,不要學的太寬泛,而成爲泛而不精的人,最後一無可取。最近這一年確實太癡迷(yilai)於框架(React),基礎關注的太少。框架與基礎,框架層出不窮,但基礎只是持續在演進。