需要綁定的原因
事件綁定目的,就是事件的作用域的轉移。
問題是,react生成出來的組件,this還不能指向自身嗎?
<button onClick={this.plus}>plus</button>
plus函數上的this,是事件響應時的上下文(window),並不是當前組件實例!
先來看看bind方法的定義:“
bind()方法創建一個新的函數, 當這個新函數被調用時其this置為提供的值”,什么意思呢,看代碼:
var module = { x: 42, getX: function() { return this.x; } } var unboundGetX = module.getX; console.log(unboundGetX()); // 調用的對象是window,所以里面的this.x => window.x // expected output: undefined
var boundGetX = unboundGetX.bind(module); console.log(boundGetX()); // 但是bind之后,會將this的值置為module提供的值 // expected output: 42
所以代碼修改為 this.plus.bind(this)之后,不過執行時的上下文是什么,函數的內部的this,始終指向組件提供的值。
選擇綁定方法的目的
綁定的方法有好多種,為什么需要挑選呢?我們首先要了解到:
-
DOM 是一個獨立於語言的文檔接口 API。在瀏覽器中,該 API 是用 JavaScript 實現的。但瀏覽器通常把DOM 和 JavaScript 分開實現。所以每次 JavaScript 訪問 DOM 都會伴隨着巨大的開銷。
-
bind() 會創建一個綁定了作用域的函數實例。於是,從原型中實現一個實例,相當於拷貝了一份同樣的函數,這是一種巨大的浪費。React想要把系統的方法關聯到DOM上,我們需要最優的方法進行綁定。
而React事件系統對DOM進行了改進,有一套高效的事件的
-
注冊
-
存儲
-
分發
-
重用
的機制,得到了優秀的效果:
-
事件委托:react組件聲明的事件都會轉換成DOM原生事件
-
事件冒泡:以隊列的形式,可以回溯父組件
-
合成事件:並不是單純的使用DOM原生事件
-
對象池:合理管理事件對象,內存分配,垃圾回收
實現
-
bind方法
-
每次重新渲染時,都會生成一個新的函數實例保存在listenerBank中
-
數量多時極其浪費內存。
-
如果是子組件的props,則會導致子組件重新渲染
-
用默認參數event來解決,如【箭頭函數-函數上】,它們會在有event參數的情況下綁定到同一個函數上
<button onClick={this.handleEdit.bind(this, param)}>編輯</button>
-
箭頭函數上調用
-
實際效果同bind方法,同樣會造成重新綁定問題
-
可以帶參數,但是需要把參數寫兩次,不划算
<button onClick={(param) => this.handleEdit(param)}>編輯</button>
-
構造器內部聲明
-
官方推薦,雖然代碼量多
-
事件只會生成一個
constructor(props){ super(props); this.handleEdit = this.handleEdit.bind(this); }
-
箭頭函數聲明
-
寫法簡單
-
只會生成一個
-
不能帶參數,帶參數就要寫成bind方式
const handleEdit = (e) => { console.log(e) }
-
雙冒號語法
-
::的意思是,綁定左值和右值
-
相當於.bind(this),但是不能帶參數,不推薦
<button onClick={::this.click}></button
當組件的事件數量極多時,用【構造器內部聲明】方法,否則就犧牲性能來換取便捷,有參數就用【bind方法】,沒有就用【箭頭函數聲明】。這是又一個性能與業務平衡的例子。
思考
-
為什么在VUE中的事件不需要綁定?
<button v-on:click="say('what')">Say what</button
來看看官方原文:
印證了那句話:VUE是保時捷,react是組裝車。
-
jQuery需要事件綁定嗎?
需要。但是為了不破壞DOM的結構,並不是直接綁定在DOM上,而是通過一種緩存的方式監聽數據。
