专栏首页Tz一号react的事件处理为什么要bind this 改变this的指向?

react的事件处理为什么要bind this 改变this的指向?

react的事件处理会丢失this,所以需要绑定,为什么会丢失this?

首先来看摘自官方的一句话:

You have to be careful about the meaning of this in JSX callbacks. In JavaScript, class methods are not bound by default.

这句话大概意思就是,你要小心jax回调函数里面的this,class方法默认是不会绑定它的

让我十分疑惑,在我的知识范围理解中,class是es6里面新增的方法,不就用来继承原有对象上的属性和方法创建新的对象吗?就是代替原来的构造函数的一种更清晰的方式,为什么就不会绑定this呢?

可是查阅了一些es6的文档,并不是这样的啊,和class方法没啥关系吧,为什么要它背锅呢?

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};

    // This binding is necessary to make `this` work in the callback
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.setState(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }));
  }

  render() {
    return (
      <button onClick={this.handleClick}> //这里调用的this也能拿到啊??
        {this.state.isToggleOn ? 'ON' : 'OFF'} //这里的this为什么没问题?
      </button>
    );
  }
}

这是官网上的一段代码,如果是是因为class的关系,handleClick里面拿不到this,那为什么render里面能拿到this,所以和class根本没关系吧本来就能拿到,那问题出现在哪里,为什么拿不到?

先看看解决办法

第一种,在constructor里面用bind绑定this

constructor(props) {
    super(props);
    this.state = {isToggleOn: true};

    // This binding is necessary to make `this` work in the callback
    this.handleClick = this.handleClick.bind(this);
  }

第二种,声明方法的时候使用箭头函数

  handleClick = () => {
    this.setState(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }));
  }

第三种,调用的时候使用箭头函数

render() {
    return (
      <button onClick={ () => { this.handleClick } }> 
        {this.state.isToggleOn ? 'ON' : 'OFF'} 
      </button>
    );
  }

  这个时候我想起了原生dom绑定click的方法

<button onclick ="handleClick()">点我</button>

  两者比较,我发现了个区别,原生的绑定方法事件名后面多了个() 于是我尝试着在react里面的事件加一个()

render() {
    return (
      <button onClick={ this.handleClick() }> 
        {this.state.isToggleOn ? 'ON' : 'OFF'} 
      </button>
    );
  }

就像上面这样,然后我发现,无论我怎么点,都不会触发这个方法了,再细心点,就发现,在渲染的时候,就调用了一次,而且仅此一次,再也不能调用了.

原因是jsx语法,渲染的时候会把{}里面包裹的代码先解析一遍,因为如果加了括号,直接就执行了里面的函数,就没有东西了,但是这个时候,this是可以拿到的

class App extends Component {
  handleClick(){
      console.log(this); //下面调用加了(),这个时候发现,this是可以拿到的
  }
  render() {
    return (
      <div className="App">
        <button onClick={this.handleClick()}>点我</button> //这里加了括号的
      </div>
    );
  }
}

  好像问题越来越明朗了,为啥会拿不到,和class没有关系,完全是因为react自己封装的东西,先会把{}里面的代码解析一遍,于是大概就是下面这种情况了

const obj = {
        num:1
    }
    obj.handleClick = function () {
        console.log(this);
    }
    console.log(eval(obj.handleClick ));  // f(){ console.log(this) } react对{}的解析
    (eval(obj.handleClick))() //onclick触发点击事件 这里输出this是window,所以就等于丢失了this指向

    console.log(eval(() => { obj.handleClick() }));  // () => { obj.handleClick() } react对{}的解析
    (eval(() => {obj.handleClick()}))() //onclick触发点击事件 这里输出this还是obj,所以this就保留了

  所以问题出在react对{}的解析会把this的指向解除了

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 深度剖析前端JavaScript中的原型(JS的对象原型)

    JavaScript 常被描述为一种基于原型的语言 (prototype-based language)——每个对象拥有一个原型对象,对象以其原型为...

    Tz一号
  • 没有用到React,为什么我需要import引入React?

    本质上来说JSX是React.createElement(component, props, ...children)方法的语法糖。

    Tz一号
  • (Demo分享)利用原生JavaScript-ScrollLeft-实现做轮播广告通知

    Tz一号
  • php用select实现I/O复用

    在Linux Socket服务器短编程时,为了处理大量客户的连接请求,需要使用非阻塞I/O和复用,select、poll和epoll是Linux API提供的I...

    gaobinzhan
  • 如何用 vue 制作一个探探滑动组件

    前言 嗨,说起探探想必各位程序汪都不陌生(毕竟妹子很多),能在上面丝滑的翻牌子,探探的的堆叠滑动组件起到了关键的作用,下面就来看看如何用vue写一个探探的堆叠组...

    程序员宝库
  • RocketMQ存储--主从同步【源码笔记】

    1.消息存储在Master上了,如何同步到Slave上了呢? 2.同步复制和异步复制流程是怎么样的?

    瓜农老梁
  • React 深入系列5:事件处理

    iKcamp
  • 再也不用被this苦恼了

    前端编程对于this再熟悉不过了,今日来个老调重弹温故知新,肯定有很多大佬已经完全吃透了this原理,敬请出门左拐。对于理解this似懂非懂的同学可以借鉴一波

    Jack Chen

扫码关注云+社区

领取腾讯云代金券