[ReactDoc] 處理事件 Handling Events
重要觀念
Event Pooling and Synthetic Event
❗ 記得把在 event 中使用到的變數先存起來,才能避免 synthetic event 的錯誤訊息(如下):
This synthetic event is reused for performance reasons. If you're seeing this, you're accessing the property
target
on a released/nullified synthetic event. This is set to null. If you must keep the original synthetic event around, use event.persist(). See react-event-pooling for more information.
解決方式除了使用 event.persist()
之外,也可把該 event
先存成一個變數,例如:
const handleClick = (e) => {
const target = e.target; // 先把 e.target 存成一個變數
console.log(target);
};
Event Pooling @ React Docs
Code Snippets
this 的綁定
function component:無法綁定 this
// Stateless Functional Component
function ActionLink() {
// STEP 2: 定義 event handler
function handleClick(e) {
e.preventDefault();
console.log('The link was clicked.');
}
return (
// STEP 1: 監聽事件
<a href="#" onClick={handleClick}>
Click me
</a>
);
}
❗ **stateless function component 中的
this
會指稱到Window**
。
Class component
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = { isToggleOn: true };
// STEP 3: 綁定 event handler 的 this
this.handleClick = this.handleClick.bind(this);
}
// STEP 2: 定義 event handler
handleClick(e) {
this.setState((prevState) => ({
isToggleOn: !prevState.isToggleOn,
}));
}
render() {
return (
// STEP 1: 監聽事件
<button onClick={this.handleClick}>{this.state.isToggleOn ? 'ON' : 'OFF'}</button>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Toggle />);
Class component with Public Class Fields syntax
class LoggingButton extends React.Component {
// 如果有支援 public class fields 這種語法(實驗性)
// 可以透過這樣綁定 this
handleClick = (e) => {
console.log('this is:', this);
}
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
);
}
在事件中代入其他參數(parameters)
class Toggle extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(id, e) {
// Do something here ...
}
}
<button onClick={(e) => this.handleClick(id, e)}>Delete Row</button>
<button onClick={this.handleClick.bind(this, id)}>Delete Row</button>
- 使用的是箭頭函數,則代入參數的順序可以自己決定。
- 使用的是
bind
,則 event handler 的最後一個參數一定會是event
。 - 這兩種方法都不是最好的寫法,因為都會在該元件轉譯時,重複產生同樣內容的 function。
最好的寫法可以是這樣
class Toggle extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
// 可以簡寫成 handleClick = params => e => {...}
// !!下面這種寫法若沒有使用 arrow function 則 this 會變成 undefined
handleClick(params) {
return (e) => {
// Do something here ...
};
} // /handleClick
}
<button onClick={this.handleClick('params')}>Delete Row</button>;
參考
- Handling Events @ ReactJS Main Concepts
- SyntheticEvents @ ReactJS API
- ReactJS - Parameterized Event Handlers @ Medium