react随笔5 事件处理

2019-04-21  本文已影响0人  _fan凡

事件处理

React元素的事件处理和DOM元素的事件处理很相似,但是有一点语法上的不同:

<button onclick="activateLasers()">Activate Lasers</button>

React中写法:

<button onClick={activateLasers}>Activate Lasers</button>

可以看到,传统HTML中点击事件的属性名是小写的onclick,而React中是驼峰式的onClick;点击事件的值,传统的HTML中是一个字符串,字符串的值就是处理函数的名称:activateLasers(),而React中采用的JSX语法,点击事件的值就是这个函数名称:activateLasers

<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框中,如下图:

image.png
上面是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:如下:

image.png
这并不是React的特殊行为,他是函数如何在JavaScript中运行的一部分。如果没有在方法后面添加(),例如onClick={this.handleClick},那就需要在constructor方法中为handleClick这个方法绑定this。当然可以在后边机上(),但是这样在初始化的时候就直接执行了,达不到我们想要的效果,图下图:
image.png
如果不想使用绑定,还有另外两种解决方式:
class ActionLink extends React.Component {
  handleClick = () => {
    console.log(this);
  }

  render() {
    return (<a href="#" onClick={this.handleClick}>click me</a>);
  }
}

如下图:


image.png
class ActionLink extends React.Component{
  handleClick(e) {
    console.log(e);
    console.log(this);
  }
  
  render(){
    return (<a href="#" onClick={(e) => this.handleClick(e)}></a>);
  }
}

如下图:

image.png
注意:使用这个语法有个问题,每次组件有变化需要重新渲染的时候,都会创建一个不同的回调函数。在多数情况下,没有问题。但是如果这个回调函数作为一个属性值传入低阶组件,那么这些组件可能会进行额外的重新渲染。

向事件处理程序传递参数

通常我们会给事件处理程序传递额外的参数,进行不同的操作。例如,若是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>
        );
    }
}
上一篇下一篇

猜你喜欢

热点阅读