React組件中綁定回調(diào)

原文:Binding callbacks in React components

在組件中給事件綁定處理函數(shù)是很常見的雪情,比如說每當(dāng)用戶點(diǎn)擊一個button的時候使用console.log打印一些東西椭住。

class DankButton extends React.Component {
  render() {
    return <button onClick={this.handleClick}>Click me!</button>
  }
  
  handleClick() {
    console.log(`such knowledge`)
  }
}

很好,這段代碼會滿足你的需求旋廷,那現(xiàn)在如果我想在handleClick()內(nèi)調(diào)用另外一個方法,比如logPhrase()

class DankButton extends React.Component {
  render() {
    return <button onClick={this.handleClick}>Click me!</button>
  }
  
  handleClick() {
    this.logPhrase()
  }
  
  logPhrase() {
    console.log('such gnawledge')
  }
}

這樣竟然不行礼搁,會得到如下的錯誤提醒

TypeError: this.logPhrase is not a function at handleClick (file.js:36:12)

當(dāng)我們把handleClick綁定到 onClick的時候我們傳遞的是一個函數(shù)的引用饶碘,真正調(diào)用handleClick的是事件處理系統(tǒng)。因此handleClickthis上下文和我門想象的this.logPhrase()是不一樣的馒吴。

這里有一些方法可以讓this指向DankButton組件扎运。

不好的方案1:箭頭函數(shù)

箭頭函數(shù)是在ES6中引入的,是一個寫匿名函數(shù)比較簡潔的方式饮戳,它不僅僅是包裝匿名函數(shù)的語法糖豪治,箭頭函數(shù)沒有自己的上下問调衰,它會使用被定義的時候的this作為上下文喜喂,我們可以利用這個特性宦芦,給onClick綁定一個箭頭函數(shù)蒙揣。

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')
  }
}

然而渐排,我并不推薦這種解決方式,因為箭頭函數(shù)定義在render內(nèi)部戈轿,組件每次重新渲染都會創(chuàng)建一個新的箭頭函數(shù)玻侥,在React中渲染是很快捷的,所以重新渲染會經(jīng)常發(fā)生涣脚,這就意味著前面渲染中產(chǎn)生的函數(shù)會堆在內(nèi)存中示辈,強(qiáng)制垃圾回收機(jī)制清空它們,這是很花費(fèi)性能的遣蚀。

不好的方案2:this.handleClick.bind(this)

另外一個解決這個問題的方案是矾麻,把回調(diào)綁定到正確的上下問this

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')
  }
}

這個方案和箭頭函數(shù)有同樣的問題,在每次render的時候都會創(chuàng)建一個新的函數(shù)芭梯,但是為什么沒有使用匿名函數(shù)也會這樣呢险耀,下面就是答案。

function test() {}

const testCopy = test
const boundTest = test.bind(this)

console.log(testCopy === test) // true
console.log(boundTest === test) // false

.bind并不修改原有函數(shù)玖喘,它只會返回一個指定執(zhí)行上下文的新函數(shù)(boundTest和test并不相等)甩牺,因此垃圾回收系統(tǒng)仍然需要回收你之前綁定的回調(diào)。

好的方案:在構(gòu)造函數(shù)(constructor)中bind handleClick

仍然使用 .bind 累奈,現(xiàn)在我們只要繞過每次渲染都要生成新的函數(shù)的問題就可以了贬派。我們可以通過只在構(gòu)造函數(shù)中綁定回調(diào)的上下問來解決這個問題,因為構(gòu)造函數(shù)只會調(diào)用一次澎媒,而不是每次渲染都調(diào)用搞乏。這意味著我們沒有生成一堆函數(shù)然后讓垃圾回收系統(tǒng)清除它們。

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')
  }
}

很好戒努,現(xiàn)在我們的函數(shù)被綁定到正確的上下文请敦,而且不會在每次渲染的時候創(chuàng)建新的函數(shù)。

如果你使用的是React.createClass而不是ES6的classes储玫,你就不會碰到這個問題冬三,createClass生成的組件會把它們的方法自動綁定到組件的this,甚至是你傳遞給事件回調(diào)的函數(shù)缘缚。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末勾笆,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子桥滨,更是在濱河造成了極大的恐慌窝爪,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件齐媒,死亡現(xiàn)場離奇詭異蒲每,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)喻括,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進(jìn)店門邀杏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事望蜡』秸福” “怎么了?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵脖律,是天一觀的道長谢肾。 經(jīng)常有香客問我,道長小泉,這世上最難降的妖魔是什么芦疏? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮微姊,結(jié)果婚禮上酸茴,老公的妹妹穿的比我還像新娘。我一直安慰自己兢交,他們只是感情好弊决,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著魁淳,像睡著了一般。 火紅的嫁衣襯著肌膚如雪与倡。 梳的紋絲不亂的頭發(fā)上界逛,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天,我揣著相機(jī)與錄音纺座,去河邊找鬼息拜。 笑死,一個胖子當(dāng)著我的面吹牛净响,可吹牛的內(nèi)容都是我干的少欺。 我是一名探鬼主播,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼馋贤,長吁一口氣:“原來是場噩夢啊……” “哼赞别!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起配乓,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤仿滔,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后犹芹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體崎页,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年腰埂,在試婚紗的時候發(fā)現(xiàn)自己被綠了飒焦。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡屿笼,死狀恐怖牺荠,靈堂內(nèi)的尸體忽然破棺而出翁巍,到底是詐尸還是另有隱情,我是刑警寧澤志电,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布曙咽,位于F島的核電站,受9級特大地震影響挑辆,放射性物質(zhì)發(fā)生泄漏例朱。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一鱼蝉、第九天 我趴在偏房一處隱蔽的房頂上張望洒嗤。 院中可真熱鬧,春花似錦魁亦、人聲如沸渔隶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽间唉。三九已至,卻和暖如春利术,著一層夾襖步出監(jiān)牢的瞬間呈野,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工印叁, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留被冒,地道東北人。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓轮蜕,卻偏偏與公主長得像昨悼,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子跃洛,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評論 2 345

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理率触,服務(wù)發(fā)現(xiàn),斷路器汇竭,智...
    卡卡羅2017閱讀 134,600評論 18 139
  • 這篇筆記主要包含 Vue 2 不同于 Vue 1 或者特有的內(nèi)容闲延,還有我對于 Vue 1.0 印象不深的內(nèi)容。關(guān)于...
    云之外閱讀 5,045評論 0 29
  • 深入JSX date:20170412筆記原文其實(shí)JSX是React.createElement(componen...
    gaoer1938閱讀 8,048評論 2 35
  • 在線閱讀 http://interview.poetries.top[http://interview.poetr...
    程序員poetry閱讀 114,266評論 24 450
  • 1. this之謎 在JavaScript中韩玩,this是當(dāng)前執(zhí)行函數(shù)的上下文垒玲。因為JavaScript有4種不同的...
    百里少龍閱讀 988評論 0 3