React中this值繫結和事件函式傳參

wuzhengyan2015發表於2018-07-15

Javascript中的this值總是能讓很多初學者感到困惑,總的來說this值就是指向呼叫函式的那個物件。但是call, apply, bind方法和ES6中箭頭函式讓this值還是要具體情況具體分析,不過這塊知識點並不是很難,對應的部落格也很多,花點時間就能掌握。接下來主要介紹React中this值繫結和事件函式傳參。

React中this值繫結

React中也有this值的繫結問題,接下來將介紹五種繫結模式。

使用React.createClass

如果你使用React.createClass來建立元件,那麼React會自動把函式中的this值指向元件例項。

React.createClass({
    getInitialState: function() {
        return {
            text: 'text'
        };
    },
    handleChange: function(event) {
        this.setState({
            text: event.target.value
        });
    },
    render: function() {
        return (
            <div>
                Type something:
                <input onChange={this.handleChange} value={this.state.text} />
            </div>
        )
    }
})
複製程式碼

上面的例子中inputonChange處理函式直接指向了handleChange方法,在使用React.createClass方法建立元件中這是可行的。

要注意的是,React.createClass在React 16.0.0 版本中就從核心包移除出去了,要從 create-react-class 中獲取。

同時官方是推薦使用 ES6 類語法來進行元件的定義,所以這個this值的繫結方法是不推薦的。

在Render函式中繫結

通常我們都是使用 ES6 類語法來進行元件的定義,此時 React 並不會自動繫結 this值。一種解決方法是在render函式中進行 this值繫結:

onChange={this.handleChange.bind(this)}
複製程式碼

這種方法簡明清晰,但是對效能會有些影響,因為每次渲染時都會使用bind方法建立一個新函式。

在Render函式中使用箭頭函式

這個方法和使用bind函式有些類似,你可以在render中使用箭頭函式來保證this值是指向元件例項的。

onChange={e => this.handleChange(e)}
複製程式碼

同樣的這種方法也是對效能有影響的,箭頭函式每次渲染時都要重新建立。

在建構函式中進行繫結

在建構函式中進行this值的繫結應該是大多數人在使用的,它避免了每次渲染時都要重新建立事件方法。

constructor(props) {
  super(props);
  this.handleChange = this.handleChange.bind(this);
}
複製程式碼

但是有時方法比較多的情況下,建構函式中充滿了繫結方法,顯得很冗長。

定義類屬性的時候使用箭頭函式

這種語法還在提案階段,你可以使用transform-class-properties 或者 Babel 中的 stage-2 來完成轉碼。

handleChange = () => {
  // call this function from render 
  // and this.whatever in here works fine.
}
複製程式碼

箭頭函式的this中是指向外層作用域中this值的。所以這個方法中this值總是指向元件例項的,同時它也不會也上邊提到的效能問題。所以說推薦使用這種方法來處理this的繫結。

事件傳參

講完了this值的繫結,接下來快速討論下事件函式的傳參問題。

簡單快速的方法

  • 在使用bind函式的時候進行傳參。
<th value={column} onClick={this.handleSort.bind(null, column)}>{column}</th>
複製程式碼

這邊提一下,event物件也會在你的傳輸後面預設傳入。

  • 箭頭函式傳參
<th value={column} onClick={(event) => this.handleSort(column, event)}>{column}</th>
複製程式碼

從DOM元素屬性中獲取

handleSort(event) {
    const value = event.target.getAttribute('value')
}

<th value={column} onClick={this.handleSort}>{column}</th>
複製程式碼

抽離出一個子元件

抽離出一個子元件,這樣可以避免渲染時一直重新建立事件函式導致的效能問題。

首先主模組:

{this.props.defaultColumns.map((column) => (
  <TableHeader
    value={column}
    onHeaderClick={this.handleSort}
  />
))}
複製程式碼

子元件:

class TableHeader extends Component {
  handleClick = () => {
    this.props.onHeaderClick(this.props.value);
  }

  render() {
    return (
      <th onClick={this.handleClick}>
        {this.props.column}
      </th>
    );
  }
}
複製程式碼

子元件繼承PureComponent只會在props發生改變時才會重新渲染(自動淺比較)。

這個最佳實踐在eslint-plugin-react中也是有的,所以推薦寫程式碼時開啟Eslint。

總結

  • this值的繫結首先推薦使用類屬性箭頭函式的方式來處理,其次是在建構函式中進行繫結。
  • 事件函式傳參可以抽離一個子元件或者從DOM屬性獲取來完成。不考慮效能可能在render函式中進行傳參。

相關文章