當你使用 ES6 class
語法定義一個組件的時候,通常的做法是將事件處理函數聲明爲 class
中的方法。例如,下面的 Toggle
組件會渲染一個讓用戶切換開關狀態的按鈕:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>事件處理中this</title>
<script src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<!-- <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script> -->
<!-- <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script> -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
class Toggle extends React.Component {
constructor(props) {
super(props)
this.state = { isToggleOn: false }
}
handleClick() {
console.log(this) // undefined
this.setState((state, props) => ({
isToggleOn: !state.isToggleOn
}))
// 大括號外需要加小括號
// 原因:因爲箭頭函數寫法()=>{}後面的大括號作爲函數體,
// 如果上面(state, props) => {isToggleOn: !state.isToggleOn}不加上()則大括號裏面isToggleOn: !state.isToggleOn將作爲函數體執行,明顯裏面內容不是執行語句。
// 如果加上小括號,(state, props) => ({isToggleOn: !state.isToggleOn})的函數體就相當於返回一個{isToggleOn: !state.isToggleOn}對象
}
render() {
return (
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'on' : 'off'}
</button>
)
}
}
ReactDOM.render(
<Toggle />,
document.getElementById('root')
)
</script>
</body>
</html>
當瀏覽器執行上述腳本代碼時會發生如下錯誤:
錯誤產生的原因是因爲onClick={this.handleClick}
僅僅傳入了函數的引用,並沒有綁定執行函數this
指向,所以this
值是undefined
,this.setState
就找不到setState
。
既然沒有綁定函數的this
指向,我們有以下兩種方式指定this
:
- 1、使用
bind
綁定this
constructor(props) {
super(props)
this.state = { isToggleOn: false }
this.handleClick = this.handleClick.bind(this)
}
或者
render() {
return (
<button onClick={this.handleClick.bind(this)}>
{this.state.isToggleOn ? 'on' : 'off'}
</button>
)
}
- 2、回調函數採用調用式
render() {
return (
<button onClick={() => this.handleClick()}>
{this.state.isToggleOn ? 'on' : 'off'}
</button>
)
}
handleClick
函數調用者是this(Toggle對象)
,所以函數內部this
也指向Toggle
對象