目錄

React.js 到底要在哪 bind this ?

TL;DR class property + arrow function 才是王道

情境: 假設你有一個<Button />元件,其 onClick 中會需要時使用 this.propsthis.state

這時就會需要將 onClick function 綁定元件的 this

而綁定 this 的方式有以下幾種:

1. 直接透過.bind 綁定

1
<Button onClick={this.handleClick.bind(this)} />

2. 於 render 時,使用箭頭函式

1
<Button onClick={(e) => this.handleClick(e)} />

3. 在 class component 的 constructor 中綁定

1
2
3
4
5
6
7
    constructor(){
     this.handleClick = this.handleClick.bind(this)
    }

    render(){
      <Button onClick={this.handleClick}/>
    }

4. 於 class properties 使用箭頭函式

1
2
3
4
5
    handleClick = () => {  }

    render(){
      <Button onClick={this.handleClick}/>
    }

使用 class properties 宣告箭頭函式,可以發現若直接由 console.log() 印出該 class,其 prototype 中是看不到 class property 所宣告的箭頭函式,但卻有其他一般的函式。


因為這種寫法經過 webpack、bable 轉譯後,會被丟到 constructor 中,變成

1
2
3
    constructor(){
     this.handleClick = () => {  }
    }

既然被放到建構子,表示必須在實例化之後才看得到這個屬性,且繼承後的新 class 也無法使用 super.handleClick()


哪一種方式比較好?

其中,1 和 2 會在每次 render 都產生新 function,此時會造成一個現象:

父元件因 props/state 改變而需重新渲染時,onClick function 因為被重新產生,被 react 視為有改變,造成其子元件也被重新渲染

這種多餘的渲染其實是不必要的,有可能影響元件效能;

而 3 和 4,是當元件被建構時,將 handleClick 存於 this 中,在每次渲染時並沒有重新產生 function。

另外,在 ES7 proposal 的功能中,有一個 bind operatror — 雙冒號:: 用法如下:

1
<Button onClick={::this.handleClick} />


bind operator 若是由 babel 轉譯,會轉成上述的第 3 種 this.handleClick.bind(this)

more details

有時候表單欄位一多,但 onChange 事件又大同小異時,可以動態產生 onChange:

1
2
3
handleChange = (name) => (e) => {
  this.setState({ [name]: e.target.value });
};


BUT…這其實也有相同問題,會產生新的函式,有一個龜毛一點的方式可以避免產生新 function:

1
2
3
4
5
6
7
8
handleChange = (name) => {
  if (!this.handlers[name]) {
    this.handlers[name] = (e) => {
      this.setState({ [name]: e.target.value });
    };
  }
  return this.handlers[name];
};

越來越複雜了… 個人感想是,當需要綁定的 handler 很多,再考慮把 function 存起來,否則讓 function 動態產生,可讀性較佳


參考資料