代碼以下:html
class test extends Component { constructor(props) { super(props); this.state = { liked: false }; } handleClick(event) { this.setState({liked: !this.state.liked}); } render() { var text = this.state.liked ? '喜歡' : '不喜歡'; return ( <div onClick={this.handleClick}> 你<b>{text}</b>我。點我切換狀態。 </div> ); } } export default test;
能夠正常展現頁面:
可是按鈕點擊就會報錯。
爲何會出現這種狀況?
由於點擊按鈕是,到了handleClick() 方法中的this 已經不是組件裏的this了。
第一種解決方法是: 手動綁定this。將react
constructor(props) { super(props); this.state = { liked: false }; }
改成git
constructor(props) { super(props); this.state = { liked: false }; this.handleClick = this.handleClick.bind(this);//手動綁定 }
第二種解決方法是: 將github
handleClick(event) { this.setState({liked: !this.state.liked}); }
改成web
handleClick= (e) => { this.setState({liked: !this.state.liked}); }
這種解決方法之因此能解決問題,就是引伸到了另一個問題: 函數做爲react 組件的方法時,箭頭函數和普通函數的卻別是什麼?
舉個栗子: 下面2個a 的區別定義有什麼區別?babel
class App extends Component { a() { console.log(1) } a = () => { console.log(1) } }
第一個a沒必要說,是原型方法的定義,寬鬆模式下對應ES5 就是svg
App.prototype.a = function() {}
第二個是 Stage 2 Public Class Fields 裏面的寫法,babel 下須要用 Class properties transform Plugin 進行轉義。至關於:函數
class App extends Component { constructor (...args) { super(...args) this.a = () => { console.log(1) } } }
爲何須要第二種寫法?
在react 裏邊,要講類的原型方法經過props 傳給子組件,傳統寫法必需要bind(this),不然方法執行時this會找不到:優化
<button onClick={this.handleClick.bind(this)}></button>
或者this
<button onClick={(e) => this.handleClick(e)}></button>
這種寫法難看不說,還會對react組件的 shouldComponentUpdate 優化形成影響。
這是由於react提供了shouldComponentUpdate 讓開發者可以控制避免沒必要要的render,還提供了再shouldComponentUpdate自動進行 Shallow Compare 的react.PUreComponent 繼承自 PureComponent 的組件,只要props和state 中的值不變,組件就不會從新render。
然而若是用了bind this,每次父組件渲染,傳給子組件的props.onClick 都會變,PureComponent 的 Shallow Compare 基本上就是小了,除非你手動實現
shouldComponentUpdate
使用 Public Class Fields 的這種寫法,就解決了這個問題。靈位還有其餘若干種辦法,好比先定義原型方法,而後在constructor 裏邊bind 一遍,或者使用decorator 進行bind 等:
class A { constructor() { this.a = this.a.bind(this) } a() {} // or @bindthis b() {} }
而箭頭函數除了代碼少,與普通函數最大的不一樣就是: this 是由聲明該函數時候定義的,通常是隱性定義爲聲明該函數時的做用域this。
var a = ()=>{ console.log(this) } //等同於 var a = function(){ console.log(this) }.bind(this); a(); //Window var b = function(){ console.log(this) }; b(); //Window var obj = { a,b }; obj.a(); //Window obj.b(); //obj
箭頭函數最大的做用是使得this 從正常狀況下的動態做用域(根據運行位置肯定值)變成了靜態做用域(根據定義位置肯定值,也就是詞法做用域)。
若想了解得更詳細,能夠去閱讀官方文檔:https://reactjs.org/docs/handling-events.html