009-处理事件
一、概述
使用React元素处理事件与处理DOM元素上的事件非常相似。有一些语法差异:
- React事件使用camelCase命名,而不是小写。
- 使用JSX,您将传递函数作为事件处理函数,而不是字符串。
二、区别
2.1、调用事件区别
例如,HTML:
<button onclick="activateLasers()">
Activate Lasers
</button>
在React中略有不同:
<button onClick={activateLasers}>
Activate Lasers
</button>
2.2、调用当前页区别
您无法返回false
以防止React中的默认行为。你必须preventDefault
明确地调用。
例如,对于纯HTML,为了防止打开新页面的默认链接行为,您可以编写:
<a href="#" onclick="console.log('The link was clicked.'); return false">
Click me
</a>
在React中,这可能是:
function ActionLink() { function handleClick(e) { e.preventDefault(); console.log('The link was clicked.'); } return ( <a href="#" onClick={handleClick}> Click me </a> ); }
这里e
是一个综合事件。React根据W3C规范定义了这些合成事件,因此您不必担心跨浏览器兼容性。请参阅SyntheticEvent
参考指南了解更多信息。
使用React时,通常不需要调用addEventListener
添加侦听器到DOM元素后创建。相反,只需在元素初始呈现时提供侦听器。
2.3、事件处理器成为该类的一个方法
当你使用ES6类定义一个组件时,一个常见的模式是让一个事件处理器成为该类的一个方法。例如,这个Toggle
组件呈现一个按钮,让用户在“ON”和“OFF”状态之间切换:
class Toggle extends React.Component { constructor(props) { super(props); this.state = {isToggleOn: true}; // This binding is necessary to make `this` work in the callback this.handleClick = this.handleClick.bind(this); } handleClick() { this.setState(prevState => ({ isToggleOn: !prevState.isToggleOn })); } render() { return ( <button onClick={this.handleClick}> {this.state.isToggleOn ? 'ON' : 'OFF'} </button> ); } } ReactDOM.render( <Toggle />, document.getElementById('root') );
您必须小心JSX回调的含义。在JavaScript中,类方法默认没有绑定。如果你忘记绑定
this.handleClick
并传递给它onClick
,this
将会在undefined
实际调用该函数时出现。
这不是特定于React的行为; 它是JavaScript中如何使用函数的一部分。一般来说,如果你引用一个没有()
后面的方法,比如onClick={this.handleClick}
你应该绑定那个方法。
如果调用bind
让你恼火,有两种方法可以解决这个问题。如果您使用的是实验性公共类字段语法,则可以使用类字段来正确地绑定回调:
class LoggingButton extends React.Component { // This syntax ensures `this` is bound within handleClick. // Warning: this is *experimental* syntax. handleClick = () => { console.log('this is:', this); } render() { return ( <button onClick={this.handleClick}> Click me </button> ); } }
这个语法在Create React App中是默认启用的。
如果您不使用类字段语法,则可以在回调中使用箭头函数:
class LoggingButton extends React.Component { handleClick() { console.log('this is:', this); } render() { // This syntax ensures `this` is bound within handleClick return ( <button onClick={(e) => this.handleClick(e)}> Click me </button> ); } }
这个语法的问题是每次LoggingButton
渲染都会创建一个不同的回调函数。在大多数情况下,这很好。但是,如果将此回调作为道具传递给较低组件,则这些组件可能会进行额外的重新渲染。我们通常建议在构造函数中绑定或使用类字段语法来避免此类性能问题。
2.3、将参数传递给事件处理程序
在循环内部,通常需要将一个额外的参数传递给事件处理程序。例如,如果id
是行ID,则以下任一项都可以工作:
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button> <button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
以上两行相同,分别使用箭头函数和箭头函数Function.prototype.bind
。
在这两种情况下,e
表示React事件的参数都将作为ID之后的第二个参数传递。使用箭头函数,我们必须明确地传递它,但是bind
任何更多的参数都会自动转发。