六、事件处理
使用React元素处理事件与处理DOM元素上的事件非常相似。不过有一些语法上的差异:
-
React事件使用驼峰命名法,而不是全部小写命名。
-
使用JSX你传递一个函数作为事件处理程序,而不是一个字符串。
例如,HTML:
<button onclick="activeLasers()">
Active Lasers
</button>
在React中略有不同:
<button onClick={activateLasers}>
Active Lasers
</button>
另一个区别是,你不能返回false
来防止React中的默认行为。 您必须显式调用preventDefault
。 例如,使用纯HTML,为了防止打开新页面的默认链接行为,您可以写:
<a href="#" onclick="console.log('The link was clicked'); return false;">
Click me
</a>
在React中,这可以改为:
function ActiveLink() {
function handleClick(e) {
e.preventDefault();
console.log('The link was clicked');
}
return (
<a href='#' onClick={handleClick}>
click me
</a>
);
}
这里,e是合成过的event。 React根据W3C规范定义这些event,因此你不需要担心浏览器兼容性的问题。
当使用React时,在创建后向DOM元素添加通常不需要调用addEventListener
监听器。 相反,只是在最初渲染元素时提供事件监听器。
当您使用ES6类定义组件时,常见的模式是将事件处理程序作为类上的公共方法。 例如,此Toggle
组件呈现一个按钮,让用户在“ON”
和“OFF”
状态之间切换:
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
// 这个绑定是必要的,要不然该事件中的this就会是当前实例
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。 如果你忘记绑定this.handleClick
中的this关键字并将它传递给了onClick
事件,当函数实际被调用时,会报出undefined
的错误。
这不是React中特定的行为; 它是JavaScript中函数正常工作的一部分。
一般来说,如果你引用一个方法是后面没有()
,如onClick = {this.handleClick}
,就会绑定该方法。
如果调用bind
会使你烦恼,有两种方法可以解决这个问题。 您可以使用属性初始值设定props来正确处理:
class LoggingButton extends React.Component {
// 使用剪头函数绑定this
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
return (
<button onClick={(e) => this.handleClick(e)}>
Click me
</button>
);
}
}
此语法的问题是,每次LoggingButton
渲染时都会创建不同的回调函数。 在大多数情况下,这是要被罚款
的。 然而,如果这个回调作为一个prop传递给较低的组件,这些组件可能会做额外的重新渲染。 我们一般建议在构造函数中绑定以避免这种性能问题。