React 事件绑定有好几种方式,我快懵了

事件处理程序(Event handlers)就是每当有事件被触发时决定要执行的动做或行为。javascript

在 React 应用中,事件名使用小驼峰格式书写,意思就是 onclick 要写成 onClickhtml

React 实现的合成事件机制给 React 应用和接口带来了一致性,同时具有高性能的优势。它经过将事件标准化来达到一致性,从而达到在不一样浏览器和平台上都具备相同的属性。java

合成事件是浏览器的原生事件的跨浏览器包装器。除兼容全部浏览器外,它还拥有和浏览器原生事件相同的接口,包括 stopPropagation()preventDefault()react

合成事件的高性能是经过自动使用事件代理实现的。事实上,React 并不将事件处理程序绑定到节点自身,而是将一个事件监听器绑定到 document 的根元素上。每当有事件被触发,React 就将事件监听器映射到恰当的组件元素上。浏览器

监听事件

在 React 中监听事件简单以下:babel

class ShowAlert extends React.Component {
  showAlert() {
    alert("Im an alert");
  }

  render() {
    return <button onClick={this.showAlert}>show alert</button>;
  }
}
复制代码

在上面的例子中,onClick 属性是咱们的事件处理程序,它被添加到目标元素上以便在元素被点击时执行要被执行的函数。onClick 属性设置了 showAlert 函数。ide

简单点儿说,就是不管什么时候点击该按钮,showAlert 函数都会被调用并显示一条信息。函数

绑定方法

在 JavaScript 中,类方法并非默认绑定的。所以,将函数绑定到类的实例上十分重要。post

render() 中绑定

这种方式是在 render 函数中调用 bind 方法来进行绑定的:性能

class ChangeInput extends Component {
  constructor(props) {
    super(props);
    this.state = {
      name: ""
    };
  }

  changeText(event) {
    this.setState({
      name: event.target.value
    });
  }

  render() {
    return (
      <div> <label htmlFor="name">Enter Text here </label> <input type="text" id="name" onChange={this.changeText.bind(this)} /> <h3>{this.state.name}</h3> </div> ); } } 复制代码

在上面的例子中,咱们使用 onChange事件处理程序在 input 输入框上监听键盘事件,该操做是经过在 render 函数中绑定完成的。该方法须要在 render 函数中调用.bind(this)

为啥呢?

任何 ES6 类中的方法都是普通的 JavaScript 函数,所以其都从 Function 的原型上继承 bind() 方法。如今,当咱们在 JSX 内部调用 onChange 时,this 会指向咱们的组件实例。

使用这种方法可能会形成一些潜在的性能问题,由于函数在每次 render 后都被从新分配一次。这种性能代价可能在小型 React 应用上并不明显,但在较大应用上就要值得注意了。

constructor() 中绑定

若是说在 render 中绑定的方法不适合你,你也能够在 constructor() 中进行绑定。例子以下:

class ChangeInput extends Component {
  constructor(props) {
    super(props);
    this.state = {
      name: ""
    };

    this.changeText = this.changeText.bind(this);
  }

  changeText(event) {
    this.setState({
      name: event.target.value
    });
  }

  render() {
    return (
      <div> <label htmlFor="name">Enter Text here </label> <input type="text" id="name" onChange={this.changeText} /> <h3>{this.state.name}</h3> </div> ); } } 复制代码

如你所见,changeText 函数绑定在 constructor 上:

this.changeText = this.changeText.bind(this)
复制代码

等号左边的 this.changeText 指向 changeText 方法,因为该步操做是在 constructor 中完成的,因此 this 指向 ChangeInput组件。

等号右边的 this.changeText 指向相同的 changeText 方法,可是咱们如今在其上调用了 .bind() 方法。

括号中的 this 做为咱们传入 .bind() 中的参数指向的是上下文(context),也就是指向 ChangeInput组件。

一样值得注意的是若是 changeText 不绑定到组件实例上的话,它就不能访问 this.setState,由于这时的 this 会是 undefined

使用箭头函数进行绑定

绑定事件处理函数的另外一种方式是经过箭头函数。经过这种 ES7 的类特性(实验性的public class fields 语法),咱们能够在方法定义时就进行事件绑定,例子以下:

class ChangeInput extends Component {
  handleEvent = event => {
    alert("I was clicked");
  };

  render() {
    return (
      <div> <button onClick={this.handleEvent}>Click on me</button> </div>
    );
  }
}
复制代码

箭头函数表达式语法比传统的函数表达式简短且没有本身的 thisargumentssupernew.target

在上面的例子中,一旦组件被建立,this.handleEvent就不会再有变化了。这种方法很是简单且容易阅读。

同在 render 函数中绑定的方法同样,这种方法也有其性能代价。

使用匿名箭头函数在 render 中绑定

绑定的时候定义一个匿名函数(箭头函数),将匿名函数与元素绑定,而不是直接绑定事件处理函数,这样 this 在匿名函数中就不是 undefined 了:

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

这种方法有一个问题,每次 LoggingButton 渲染的时候都会建立一个新的 callback 匿名函数。在这个例子中没有问题,可是若是将这个 onClick 的值做为 props 传给子组件的时候,将会致使子组件从新 render,因此不推荐。

定制组件和事件

每当谈到 React 中的事件,只有 DOM 元素能够有事件处理程序。举个栗子,好比说如今有个组件叫 CustomButton,其有一个 onClick 事件,可是当你点击时不会有任何反应,缘由就是前面所说的。

那么咱们要如何处理定制组件中的事件绑定呢?

答案就是经过在 CustomButton 组件中渲染一个 DOM 元素而后把 onClick 做为 prop 传进去,CustomButton 组件实际上只是为点击事件充当了传递介质。

class CustomButton extends Component {
  render() {
    const { onPress, children } = this.props;

    return (
      <button type="button" onClick={onPress}> {children} </button>
    );
  }
}

class ChangeInput extends Component {
  handleEvent = () => {
    alert("I was clicked");
  };

  render() {
    return (
      <div> <CustomButton onPress={this.handleEvent}>Click on me</CustomButton> </div>
    );
  }
}
复制代码

本例中,CustomButton 组件接收了一个叫 onPress 的prop,而后又给 button 传入了一个 onClick

向事件处理程序传递参数

给事件处理程序传递额外参数是很常见的,好比 id 是行 ID,下面两种传参方式均可以:

<button onClick={(e)=>this.deleteRow(id, e)}>Delete Row</button>

<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
复制代码

上面两种传参方式是等价的。

在两种传参方式中,参数 e 都表明 React 事件将要做为参数 id 后面的第二个参数来传递。区别在于使用箭头函数时,参数 e 要显示传递,可是使用 bind 的话,事件对象以及更多的参数将会被隐式的进行传递。

参考

A guide to React onClick event handlers

事件处理

React 事件绑定的正确姿式

相关文章
相关标签/搜索