React main concepts(六)
建议配合官网文档 Handling Events 进行阅读。
Handling Events
React 元素的事件处理与 DOM 的事件处理十分类似,这里有一些语法上的不同:
- React 事件使用小驼峰命名法,而不是全小写
- JSX 语法要求事件接收的参数是函数,而不是字符串
举例来说,HTML:
<button onclick="activateLasers()">
Active Lasers
</button>
和 React 有一些细微的不同:
<button onClick={activateLasers}>
Active Lasers
</button>
另一个不同是,在 React 中无法通过返回false
来阻止默认事件,而必须显式的调用preventDefault()
,例如,在 HTML 中,你可以通过以下方式取消表单的默认提交:
<from onsubmit="cnosole.log('you clicked submit'); return false;">
<button type="submit">Submit</button>
</form>
在 React 中,需要使用preventDefault()
来组织默认事件的发生:
// From 组件
function From() {
// 事件处理函数
function handleSubmit(e) {
e.preventDefault();
console.log("You clicked submit");
}
// 返回 React 元素
return (
<from onSubmit={handleSubmit}>
<button type="submit">Submit</button>
</form>
);
}
上面提到的e
是合成事件,是React 根据W3C spec生成的。因此不必担心跨浏览器的兼容问题,React 事件和原生事件不完全相同,可以参考SyntheticEvent进行详细学习。
使用 React 时,不用使用addEventListener
向已存在的 DOM 元素添加事件监听器,更常见的做法是在创建 React 时提供一个监听器。
当我们定义一个类组件时,常见的模式是将事件处理作为类的方法,例如下例中Toggle
组件渲染了一个按钮,可以切换 ON /OFF 两种状态:
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {
isToggleOn: false,
}
}
handleClick() {
// 下一状态涉及到当前状态时,需要使用函数返回对象,而不是直接写对象
this.setState(prevState => ({
isToggleOn: !isToggleOn,
)});
}
// This binding is necessary to make `this` work in the callback
this.handleClick = this.handleClick.bind(this);
render() {
return (
// 注意 JSX 中事件为小驼峰 onClick,而不是全小写 onclick
<button onClick={this.handleClick}>
{this.state.isToggleOn ? "ON" : "OFF"}
</button>
)
}
}
ReactDOM.render(<Toggle />, document.getElementById('root'));
我们必须谨慎对待 JSX 回调函数中的this
,在 JavaScript 中,类方法不会自动绑定this
,所以我们必须手动进行绑定,即this.handleClick = this.handleClick.bind(this);
。
如果你不想绑定,那么这里有两个实验性功能可以供你使用:
- 在定义类方法时使用箭头函数:
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>
);
}
} :hexoPostRenderEscape–>
2. 在回调时,使用箭头函数包裹
<!–hexoPostRenderEscape:
class LoggingButton extends React.Component {
handleClick() {
console.log(‘this is:’, this);
}
render() {
// This syntax ensures this
is bound within handleClick
return (
<button onClick={() => this.handleClick()}>
Click me
</button>
);
}
} :hexoPostRenderEscape–>
第二种方法根据其原理,可能会造成重复渲染的问题,会影响性能,因此推荐使用第一种方式,或者最初的手动绑定方法来解决。
Passing Arguments to Event Handlers
如果我们需要向事件处理函数中传入参数,一下任意两种方式都可以:
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
上面这两种方式是等价的,分别使用了箭头函数arrow functions和Function.prototype.bind
在这两种情况下,React 的事件对象 e 会被作为第二个参数传递。如果通过箭头函数的方式,事件对象必须显式的进行传递,而通过 bind 的方式,事件对象以及更多的参数将会被隐式的进行传递。