React 事件处理及 this 绑定问题

React 事件处理

React 事件是一个合成事件,JSX实际上是 React.createElement(component, props, ...children) 函数提供的语法糖表达方式,那么:

// JSX 表达
<button onClick = {this.handleClick}>
	Click me
</button>

// 经转化为
React.createElement('button', {
	onClick: this.handleClick
}, 'Click me');

可见,react事件处理可以理解为组件加载(mount)和更新(update)时,将通过addEventListener 统一注册到 docuemnt 上,然后有一个事件池存储了所有的事件,当事件触发时,通过 dispatchEvent 进行事件分发。

所以可以简单理解为,this.handleClick 作为回调函数调用。

回调函数this丢失问题,为什么要绑定this?

在函数内部,this的值取决于函数的调用方式,如下:

class Foo {
    sayThis () {
         console.log(this); // 这里的 `this` 指向谁?
     }
     exec (cb) {
         cb();
     }
    render () {
         this.exec(this.sayThis);
  }
}
var foo = new Foo();
foo.render(); // 输出结果是什么?
/*
	结果分析:输出为 undefined,
	原因:你必须谨慎对待JSX中回调函数的this,在JavaScript中,class方法默认不会绑定
	this,如果忘记了绑定 this.handleClick 并传入了 onClick,这时调用这个函数时的
	this为undefined。
	这并不是react的特有行为,与js工作原理有关,通常情况下,如果你没有在方法后面添
	加 (),例如 onClick={this.handleClick},你应该为这个方法绑定 this。
*/

为什么react没有自动把bind集成到render方法中呢?如下:

class Foo {
    sayThis () {
         console.log(this); // 这里的 `this` 指向谁?
     }

     exec (cb) {
         cb.bind(this)();
     }

    render () {
         this.exec(this.sayThis);
  }
}

var foo = new Foo();
foo.render(); // 输出结果是什么?
/*
	结果分析:Foo {}
	原因:因为render多次调用每次都要bind会影响性能,所以官方建议在constructor中手
	动bind达到性能优化。
*/
不同事件处理对比

1. 直接bind this

class Foo extends React.Component {
  handleClick () {
    this.setState({ xxx: aaa })
  }

  render() {
    return (
      <button onClick={this.handleClick.bind(this)}>
        Click me
      </button>
    )
  }
}

优点: 写起来顺手
缺点: 性能不太好,这么处理跟react给你内部绑定this没什么区别,每次render都会bind,并且不同地方使用函数都需用bind,这样会多写代码,性能不是最优的

2. constructor中手动bind

class Foo extends React.Component {
  constructor(props) {
	super(prosp);	
	this.handleClick = this.handleClick.bind(this);
  }
  handleClick () {
    this.setState({ xxx: aaa })
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        Click me
      </button>
    )
  }
}

优点 相比第一种,性能较好,因为构造函数只执行一次,那么bind只有一次
缺点 写法上不是很顺手,每次写完方法,都需要专门到constructor中bind

3. 箭头函数型

class Foo extends React.Component {
  handleClick () {
    this.setState({ xxx: aaa })
  }

  render() {
    return (
      <button onClick={(e) => {this.handleClick(e)}}>
        Click me
      </button>
    )
  }
}

优点 写法上简洁、顺手
缺点 每次render都会重复创建,性能较差

4. public class fields 型

class LoggingButton extends React.Component {
  // 此语法确保 `handleClick` 内的 `this` 已被绑定。
  // 注意: 这是 *实验性* 语法。
  handleClick = () => {
    console.log('this is:', this);
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        Click me
      </button>
    );
  }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值