原文:Binding callbacks in React componentsreact
在組件中給事件綁定處理函數是很常見的,好比說每當用戶點擊一個button的時候使用console.log
打印一些東西。函數
class DankButton extends React.Component { render() { return <button onClick={this.handleClick}>Click me!</button> } handleClick() { console.log(`such knowledge`) } }
很好,這段代碼會知足你的需求,那如今若是我想在handleClick()
內調用另一個方法,好比logPhrase()
性能
class DankButton extends React.Component { render() { return <button onClick={this.handleClick}>Click me!</button> } handleClick() { this.logPhrase() } logPhrase() { console.log('such gnawledge') } }
這樣居然不行,會獲得以下的錯誤提醒this
TypeError: this.logPhrase is not a function at handleClick (file.js:36:12)
當咱們把handleClick
綁定到 onClick
的時候咱們傳遞的是一個函數的引用,真正調用handleClick
的是事件處理系統。所以handleClick
的this
上下文和我門想象的this.logPhrase()
是不同的。code
這裏有一些方法可讓this
指向DankButton組件。component
箭頭函數是在ES6中引入的,是一個寫匿名函數比較簡潔的方式,它不單單是包裝匿名函數的語法糖,箭頭函數沒有本身的上下問,它會使用被定義的時候的this
做爲上下文,咱們能夠利用這個特性,給onClick
綁定一個箭頭函數。事件
class DankButton extends React.Component { render() { // Bad Solution: An arrow function! return <button onClick={() => this.handleClick()}>Click me!</button> } handleClick() { this.logPhrase() } logPhrase() { console.log('such gnawledge') } }
然而,我並不推薦這種解決方式,由於箭頭函數定義在render
內部,組件每次從新渲染都會建立一個新的箭頭函數,在React中渲染是很快捷的,因此從新渲染會常常發生,這就意味着前面渲染中產生的函數會堆在內存中,強制垃圾回收機制清空它們,這是很花費性能的。內存
this.handleClick.bind(this)
另一個解決這個問題的方案是,把回調綁定到正確的上下問this
get
class DankButton extends React.Component { render() { // Bad Solution: Bind that callback! return <button onClick={this.handleClick.bind(this)}>Click me!</button> } handleClick() { this.logPhrase() } logPhrase() { console.log('such gnawledge') } }
這個方案和箭頭函數有一樣的問題,在每次render
的時候都會建立一個新的函數,可是爲何沒有使用匿名函數也會這樣呢,下面就是答案。it
function test() {} const testCopy = test const boundTest = test.bind(this) console.log(testCopy === test) // true console.log(boundTest === test) // false
.bind
並不修改原有函數,它只會返回一個指定執行上下文的新函數(boundTest和test並不相等),所以垃圾回收系統仍然須要回收你以前綁定的回調。
仍然使用 .bind
,如今咱們只要繞過每次渲染都要生成新的函數的問題就能夠了。咱們能夠經過只在構造函數中綁定回調的上下問來解決這個問題,由於構造函數只會調用一次,而不是每次渲染都調用。這意味着咱們沒有生成一堆函數而後讓垃圾回收系統清除它們。
class DankButton extends React.Component { constructor() { super() // Good Solution: Bind it in here! this.handleClick = this.handleClick.bind(this) } render() { return <button onClick={this.handleClick}>Click me!</button> } handleClick() { this.logPhrase() } logPhrase() { console.log('such gnawledge') } }
很好,如今咱們的函數被綁定到正確的上下文,並且不會在每次渲染的時候建立新的函數。
若是你使用的是React.createClass
而不是ES6的classes,你就不會碰到這個問題,createClass
生成的組件會把它們的方法自動綁定到組件的this
,甚至是你傳遞給事件回調的函數。