你须要了解的 react 事件处理和绑定方法

一、事件处理

先看一个 demo

import React, { Component } from 'react';
import { render } from 'react-dom';

class LikeButton extends Component {
  constructor(props) {
    super(props);
    this.state = { liked: false };
  }

  handleClick(e) {
    this.setState({ liked: !this.state.liked });
  }

  render() {
    const text = this.state.liked ? 'like' : 'haven\'t liked';
    return (
      <p onClick={this.handleClick.bind(this)}> You {text} this. Click to toggle. </p>
    );
  }
}

render(
    <LikeButton />, document.getElementById('example') ); 复制代码

能够看到 React 里面绑定事件的方式和在 HTML 中绑定事件相似,使用驼峰式命名指定要绑定的 onClick 属性为组件定义的一个方法 {this.handleClick.bind(this)}。javascript

注意要显式调用 bind(this) 将事件函数上下文绑定要组件实例上,这也是 React 推崇的原则:没有黑科技,尽可能使用显式的容易理解的 JavaScript 代码。html

二、'合成事件'和 '原生事件'

  • React 实现了一个“合成事件”层(synthetic event system),这个事件模型保证了和 W3C 标准保持一致,因此不用担忧有什么诡异的用法,而且这个事件层消除了 IE 与 W3C 标准实现之间的兼容问题。java

  • “合成事件”还提供了额外的好处:react

2.1 事件委托

  • 事件委托就是利用事件冒泡原理,把处理任务委托给父元素或者祖先元素(一般用父元素),咱们经过目标对象来判断事件源,并执行事件处理。
  • image

“合成事件”会以事件委托(event delegation)的方式绑定到组件最上层,而且在组件卸载(unmount)的时候自动销毁绑定的事件。浏览器

2.2 原生事件

  • 好比你在 componentDidMount 方法里面经过 addEventListener 绑定的事件就是浏览器原生事件。babel

  • 使用原生事件的时候注意在 componentWillUnmount 解除绑定 removeEventListener。dom

Warning: 若是不在组件销毁的时候解除事件的话,会形成内存泄露的问题。 函数

怎么解决这个问题?这里能够看个人相关文章 react 内存泄露常见问题解决方案post

全部经过 JSX 这种方式绑定的事件都是绑定到“合成事件”,除非你有特别的理由,建议老是用 React 的方式处理事件。性能

三、事件绑定的几种方法

  • 因为类的方法默认不会绑定this,所以在调用的时候若是忘记绑定,this的值将会是undefined。 一般若是不是直接调用,应该为方法绑定this。绑定方式有如下几种:

3.一、 在构造函数中使用bind绑定this

class Button extends React.Component {
constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick(){
    console.log('this is:', this);
  }
  render() {
    return (
      <button onClick={this.handleClick}> Click me </button>
    );
  }
}
复制代码

3.二、在调用的时候使用 bind 去绑定 this

class Button extends React.Component {
  handleClick(){
    console.log('this is:', this);
  }
  render() {
    return (
      <button onClick={this.handleClick.bind(this)}> Click me </button>
    );
  }
}
复制代码

3.三、调用的时候使用箭头函数绑定 this

class Button extends React.Component {
  handleClick(){
    console.log('this is:', this);
  }
  render() {
    return (
      <button onClick={()=>this.handleClick()}> Click me </button>
    );
  }
}
复制代码

3.四、使用属性初始化语法直接绑定

class Button extends React.Component {
  handleClick=()=>{
    console.log('this is:', this);
  }
  render() {
    return (
      <button onClick={this.handleClick}> Click me </button>
    );
  }
}
复制代码

3.五、比较上诉几个方式的优劣

  • 3.2和 3.3 方法都是调用的时候再绑定 this
    • 优势: 写法简单,组件中没有 state 的时候不须要添加构造函数来绑定 this
    • 缺点: 每一次调用的时候都会生成一个新的方法实例,所以对性能有影响,而且当这个函数做为属性值传入低阶组件的时候,这些组件可能会进行额外的从新渲染,由于每一次都是新的方法实例做为的新的属性传递。
  • 3.1 方法在构造函数中绑定了 this,调用的时候不须要二次绑定
    • 优势:只会生成一个方法实例,而且绑定一次以后若是屡次用到这个方法也不须要绑定了。
    • 缺点:即便不适用 state 的时候也须要在构造函数中绑定 this,代码量多。
  • 3.4 方法 利用属性初始化语法,将方法初始化为箭头函数,所以在建立函数的时候就绑定了this。
    • 优势:建立方法就绑定this,不须要在类构造函数中绑定,调用的时候不须要再做绑定。结合了方式一、方式二、方式3的优势
    • 缺点:之前有须要 babel 转移的需求,如今随着性能愈来愈好,也会考虑这一点消耗的问。

3.6 怎么传参?

  • 给事件处理函数传递额外参数的方式:bind(this, arg1, arg2, ...)
    • 非 bind 的直接传参就能够了。
render: function() {
    return <p onClick={this.handleClick.bind(this, 'extra param')}>; }, handleClick: function(param, event) { // handle click } 复制代码

3.7 事件绑定方法总结

方式1是官方推荐的绑定方式,也是性能最好的方式。方式2和方式3会有性能影响而且当方法做为属性传递给子组件的时候会引发重渲问题。方式4是性能比较好的,如今 babel 已经很成熟了,推荐你们使用

参考

相关文章
相关标签/搜索