事件处理
React元素的事件处理和DOM元素的事件处理很相似,但是有一点语法上的不同:
- React事件绑定属性的命名采用驼峰式写法,而不是小写(DOM元素写法)。
- 如果采用了JSX的语法,需要传入一个函数作为事件处理函数,而不是一个字符串(DOM元素写法)
比如:传统的HTML:
<button onclick="activateLasers()">Activate Lasers</button>
React中写法:
<button onClick={activateLasers}>Activate Lasers</button>
可以看到,传统HTML中点击事件的属性名是小写的onclick
,而React中是驼峰式的onClick
;点击事件的值,传统的HTML中是一个字符串,字符串的值就是处理函数的名称:activateLasers()
,而React中采用的JSX语法,点击事件的值就是这个函数名称:activateLasers
。
- React(从版本v0.14开始)中不能使用返回false的方式组织默认行为。必须使用事件的preventDefault函数,传统的HTML就可以直接返回false。
比如,传统的HTML组织链接默认打开一个新页面:
<a href="https://react.docschina.org/docs/handling-events.html" onclick="console.log('The line was clicked');return false">
Click me </a>
这样点击链接Click me时,会在控制台输出The line was clicked,但是不会打开新的url地址https://react.docschina.org/docs/handling-events.html。
在React中,直接返回false是不行的。需要显示调用出发事件的preventDefault函数:
function ActionLink() {
function handleClick(e) {
e.preventDefault();
console.log('The line was clicked');
}
return (
<a href="https://react.docschina.org/docs/handling-events.html" onClick=
{handleClick} >Click me </a>
);
}
ReactDOM.render(
<ActionLink />, document.getElementById('root')
);
这里是使用函数式组件演示的,可以直接拷贝代码在这里测试。记得把上边的代码copy到JS框中,如下图:
上面是React使用函数组件来实现的,如果使用类组件,则如下:
class ActionLink extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(e) {
e.preventDefault();
console.log('The line was clicked');
}
render () {
return (<a href="https://react.docschina.org/docs/handling-events.html" onClick={this.handleClick}>Click me </a>);
};
}
ReactDOM.render(
<ActionLink />, document.getElementById('root')
);
结果如下:
image.png
在这里,e是一个合成事件。React根据W3C spce来定义这些合成事件。更多事件参考SyntheticEvent 。
使用React的时候通常不需要为DOM元素添加监听器,如使用addEventListener方法。仅仅需要在元素初始化的时候提供一个监听器。
我们也看到了,使用函数组件和类组件,事件处理函数在语法上有点区别。使用函数组件的时候,事件处理函数还是像普通的函数一样声明function handleClick() {},但是使用类组件的时候,时间处理函数就是类的一个方法,所以在定义的时候是handleClick(){},没有使用function关键字了。
我们还发现,在使用类组件的时候,在构造函数中有这么一句代码:
this.handleClick = this.handleClick.bind(this);
在render方法的返回元素中,onClick属性的值,我们使用的是JSX语法:onClic={this.handleClick},也就是点击事件的处理函数是this的handleClick方法,this代表的是当前组件。也就是点击事件其实是回调的this的handleClick方法,我们必须谨慎对待JSX回调函数中的this,类的方法默认是不会绑定this的,如果没有如上的绑定代码,即没有绑定this.handleClick,那么在handleClick这个方法中使用this的话,就会报错,this提示是undefined:如下:
这并不是React的特殊行为,他是函数如何在JavaScript中运行的一部分。如果没有在方法后面添加(),例如onClick={this.handleClick},那就需要在constructor方法中为handleClick这个方法绑定this。当然可以在后边机上(),但是这样在初始化的时候就直接执行了,达不到我们想要的效果,图下图:
image.png
如果不想使用绑定,还有另外两种解决方式:
- 1.使用实验性的属性初始化器语法
class ActionLink extends React.Component {
handleClick = () => {
console.log(this);
}
render() {
return (<a href="#" onClick={this.handleClick}>click me</a>);
}
}
如下图:
image.png
- 2.在回调函数中使用箭头函数
class ActionLink extends React.Component{
handleClick(e) {
console.log(e);
console.log(this);
}
render(){
return (<a href="#" onClick={(e) => this.handleClick(e)}></a>);
}
}
如下图:
注意:使用这个语法有个问题,每次组件有变化需要重新渲染的时候,都会创建一个不同的回调函数。在多数情况下,没有问题。但是如果这个回调函数作为一个属性值传入低阶组件,那么这些组件可能会进行额外的重新渲染。
向事件处理程序传递参数
通常我们会给事件处理程序传递额外的参数,进行不同的操作。例如,若是id是我们需要删除的那一行数据的id,那么以下两种穿残方式度可以:
<a onClick={(e) => this.handleClick(id, e)}>Delete Row</a>
<a onClick={this.handleClick.bind(this, id)}> Delete Row</a>
上述两种方法是等价的。但是需要注意的是,在使用箭头函数arrow functions的形式进行回调的时候,参数e作为React时间对象是作为第二个参数进行传递的,也就是时间独享必须显示的进行传递。但是通过bind的方式,事件对象以及更多的参数是被隐式的进行传递的。
但是通过bind方式向时间处理程序传递参数的时候,如果在事件处理程序中使用到了事件对象本身e,那么在函数定义的时候,e必须是作为参数列表的最后一个参数:
class Popper extends React.Component{
constructor(){
super();
this.state = {name:'Hello world!'};
}
preventPop(name, e){ //事件对象e要放在最后
e.preventDefault();
alert(name);
}
render(){
return (
<div>
<p>hello</p>
{/* Pass params via bind() method. */}
<a href="https://reactjs.org" onClick={this.preventPop.bind(this,this.state.name)}>Click</a>
</div>
);
}
}
网友评论