ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
# 处理事件 使用 React 元素处理事件跟在 DOM 元素上处理事件非常相似。但是有一些语法上的差别: * React 事件使用驼峰命名法,而不是小写。 * 利用 JSX 你传递一个函数作为事件处理程序,而不是一个字符串。 例如,HTML: ~~~ <button onclick="activateLasers()"> Activate Lasers </button> ~~~ 在 React 中略有不同: ~~~ <button onClick={activateLasers}> Activate Lasers </button> ~~~ 另一个区别是,在 React 中你不能通过 return false 来阻止默认行为。必须明确调用 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 规范](https://www.w3.org/TR/DOM-Level-3-Events/) 定义了这个合成事件,所以你不需要担心浏览器的兼容性。查看 [SyntheticEvent](https://facebook.github.io/react/docs/events.html) 参考指南了解更多。 当使用 React 时,你一般不需要调用 addEventListener 来 DOM 元素被创建后为它添加监听器。相反,只要当元素被初始渲染的时候提供一个监听器就可以了。 当使用一个[ ES6 类](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Classes)定义了一个组件,通常的一个事件处理程序是类上的一个方法。例如, 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') ); ~~~ 在 CodePen 中[打开查看](http://codepen.io/gaearon/pen/xEmzGg?editors=0010)。 必须小心这个 JSX 回调的意义。在 JavaScript 中,类方法默认没有[绑定](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Function/bind)。如果你忘记绑定 this.handleClick 并传递它到 onClic 上,函数实际被调用时,this 将是 underfined。 这并不是 React 特有的行为;这是[函数在 JavaScript 中的工作方式](https://www.smashingmagazine.com/2014/01/understanding-javascript-function-prototype-bind/)。通常,如果你不实用 () 引用一个方法,比如 onClick={this.handleClick},你应该绑定这个方法。 如果调用绑定使你厌烦,有两种方式可以获得解脱。如果你在使用试验性质的初始化语法,可以使用属性初始化来纠正绑定回调: ~~~ class LoggingButton extends React.Component { // 这个语法确保 `this` 被绑定在这个 handleClick 中 // 警告:这是实验性质的语法 handleClick = () => { console.log('this is:', this); } render() { return ( <button onClick={this.handleClick}> Click me </button> ); } } ~~~ 这个语法在 [创建 React App](https://github.com/facebookincubator/create-react-app) 中是默认开启的。 如果你没有使用属性初始化语法,可以在回调中使用一个[箭头函数](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions): ~~~ class LoggingButton extends React.Component { handleClick() { console.log('this is:', this); } render() { // 这个语法确保 `this` 被绑定在 handleClick 中 return ( <button onClick={(e) => this.handleClick(e)}> Click me </button> ); } } ~~~ 这个语法的问题是,每次 LoggingButton 渲染时都创建一个不同的回调。在多数情况下,这是没问题的。然而,如果这个回调被作为 pros 传递给更下层的组件,这些组件可能会有额外的重复渲染。我们通常建议在构造函数中进行绑定,以避免这类性能问题。