爲何在React Component須要bind綁定事件

咱們在 React class Component 綁定事件時,常常會經過 bind(this) 來綁定事件,好比:

class Foo extends React.Component{
  constructor( props ){
    super( props );
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick(event){
    // todo something
  }
  render(){
    return (
      <button type="button" onClick={this.handleClick}>
        Click Me
      </button>
    );
  }
}複製代碼

下面就要看爲何咱們須要bind(this)在組件中。

JavaScript 中 this 綁定機制

默認綁定(Default Binding)

function display(){
 console.log(this); // this 指向全局對象
}
display(); 複製代碼

display( )在全局的 window 做用域調用,因此函數內的 this 默認指向全局的 window, 在 strict 模式 this 的值爲undefined。

隱式綁定(Implicit binding)javascript

var obj = {
 name: 'coco',
 display: function(){
   console.log(this.name); // this 指向 obj
  }
};
obj.display(); // coco複製代碼

當咱們經過obj調用 display( ) 時,this 上下文執行 obj, 可是當咱們將 display( ) 賦給一個變量,好比:
java

var name = "oh! global";
var outerDisplay = obj.display;
outerDisplay(); // oh! global複製代碼

display 被賦給 outerDisplay 這個變量,調用 outerDisplay( ) 時,至關於 Default Binding,this 上下文指向 global, 所以 this.name 找到的是全局的 name。
不少時候,咱們須要將函數做爲參數經過callback方式來調用,也會使這個函數失去它的 this 上下文,好比:

function handleClick(callback) {
  callback()
}
var name = 'oh! global';
handleClick(obj.display);
// oh! global複製代碼

當調用handleClick方法時,JavaScript從新將 obj.display 賦予 callback 這個參數,至關於 callback = obj.display ,display這個函數在handleClick做用域環境,就像Default Binding,裏面的 this 執行全局對象。

顯式綁定(Explicit binding)bash

爲了不上面問題,咱們能夠經過 bind( ) 來顯式綁定 this 的值。
babel

var name = "oh! global";
obj.display = obj.display.bind(obj); 
var outerDisplay = obj.display;
outerDisplay();
// coco複製代碼

真正的緣由在 JavaScript 不在 React

回到開始咱們的問題:爲何 React 組件事件綁定須要 bind 來綁定,若是咱們不綁定,this 的值爲 undefined。

class Foo {
  constructor(name){
    this.name = name
  }
  display(){
    console.log(this.name);
  }
}
var foo = new Foo('coco');
foo.display(); // coco

// 下面例子相似於在 React Component 中 handle 方法看成爲回調函數傳參
var display = foo.display;
display() // TypeError: this is undefined複製代碼

咱們在實際 React 組件例子中,假設 handleClick 方法沒有經過 bind 綁定,this 的值爲 undefined, 它和上面例子相似handleClick 也是做爲回調函數傳參形式。
可是咱們代碼不是在 strict 模式下, 爲何 this 的值不是全局對象,就像前面的 default binding,而是undefined?
由於 class 類無論是原型方法仍是靜態方法定義,「this」值在被調用的函數內部將爲 undefined,具體緣由見 詳細
一樣,咱們爲了不這個問題須要 bind 綁定:

class Foo {
  constructor(name){
    this.name = name
    this.display = this.display.bind(this);
  }
  display(){
    console.log(this.name);
  }
}
var foo = new Foo('coco');
foo.display(); // coco
var display = foo.display;
display(); // coco複製代碼

固然,咱們能夠不在 constructor 中綁定 this, 好比:
函數

var foo = new Foo('coco');
foo.display = foo.display.bind(foo);
var display = foo.display;
display(); // coco複製代碼

可是,在 constructor 中綁定是最佳和最高效的地方,由於咱們在初始化 class 時已經將函數綁定,讓 this 指向正確的上下文。

不用bind 綁定方式

固然,實際寫 React Component 還有其餘的一些方式來使 this 指向這個 class :
最經常使用的 public class fields

class Foo extends React.Component{
  handleClick = () => {
    console.log(this); 
  }
 
  render(){
    return (
      <button type="button" onClick={this.handleClick}>
        Click Me
      </button>
    );
  }
}複製代碼
這是由於咱們使用 public class fields 語法,handleClick 箭頭函數會自動將 this 綁定在 Foo 這個class, 具體就不作探究。

箭頭函數
ui

class Foo extends React.Component{
  handleClick(event) {
    console.log(this); 
  }
 
  render(){
    return (
      <button type="button" onClick={(e) => this.handleClick(e)}> Click Me </button>
    );
  }
}複製代碼

這是由於在ES6中,箭頭函數 this 默認指向函數的宿主對象(或者函數所綁定的對象)。

其餘this

其餘還有一些方法來使 this 指向 Foo 上下文,好比經過 ::綁定等,具體就不展開。

總結

React class 組件中,事件的 handle 方法其實就至關於回調函數傳參方式賦值給了 callback,在執行 click 事件時
相似 element.addEventListener('click', callback, false ), handle 失去了隱式綁定的上下文,this 的值爲 undefined。(爲何是 undefined 而不是 global,上文有解釋)。
因此咱們須要在 初始化調用 constructor 就經過 bind() 綁定 this, 固然咱們不用 bind( )方式來綁定也能夠有其餘一些方法來時 this 指向正確的上下文。
相關文章
相關標籤/搜索