React事件绑定时this指向问题解决以及事件传参

本文详细探讨了React中事件处理函数的this指向问题,并提供了三种解决方法:使用bind绑定this,利用ES6 class fields语法,以及在事件监听时传入箭头函数。此外,还介绍了如何在事件处理函数中正确接收并使用参数。

React事件绑定中的this指向问题

当时如果这是我有一个需求,我点击以下按钮,来获取我们state中的数据。

btnfun(){
    console.log(this);//undefined
    console.log(this.state.data);//not undefined
}

这里为什么会出现这个问题呢?因为btnfun()函数并不是我们主动调用的,而是当触发button的事件时,react内部再去调用这个函数。而react的内部时不知道这里的this是指向哪里的。

为了解决这个问题,我们给出了三种解决方案:

方案一:使用bind为事件方法绑定this:

在使用事件方法时直接通过bind改变事件方法的指向,就像如下代码一样:

 <button onClick={this.btnfun.bind(this)}>button</button>
   btnfun(){
      console.log(this);//undefined
      console.log(this.state.data);//not undefined
    }

这是当react内部调用我们的事件函数时,就可以得知函数中的this指向何处。

上面的写法是一解决方案,但是当我们有 若干个事件都要去执行这个函数怎么办呢?我们可以使用下面这种方式进行优化。

 constructor(props) {
      super(props),
      this.state={
        data:'message'
      },
      this.btnfun=this.btnfun.bind(this)
    }

我们可以将为事件方法绑定this的操作放在构造器里,这样在后面使用时就直接使用this.btnfun 即可。

方案二:使用ES6的class fields语法

​ 这种语法是给类定义属性的方法,称之为class field语法。因为这里在赋值时使用了箭头函数,而箭头函数的this在任何情况下都会去上一个作用域中查找,而我们事件方法的上一个作用域恰巧就是当前的对象。

 btnfun=() => {
      console.log(this);//当前对象	 	
      console.log(this.state.data);//正常输出
    }

这里须知:

箭头函数体内的this对象,就是定义该函数时所在的作用域指向的对象,而不是使用时所在的作用域指向的对象。

方案三:事件监听时传入箭头函数(推荐)

​ 这种方式其实就是当给onClick事件中直接传入一个箭头函数,然后在箭头函数中进行我们的操作,可以直接写在函数中,也可以调用外部的函数。这里的this也就是箭头函数中的this,指向的时上一个作用域的this,而这里也会发生隐式绑定,将this的指向变为我们想要的结果。

写法如下:

  render() {
      return (
        <div>
          <h2>React Demo</h2>
          {/*<button onClick={this.btnfun}>button</button>*/}
          <button onClick={() => this.btnfun()}>button</button>
        </div>
      )
    }
    btnfun() {
      console.log(this);//undefined
      console.log(this.state.data);//not undefined
    }

事件参数传递

在处理事件时,有时候也会有一些需要传递的参数,最常见的就是event对象。在jsx中其实在我们的事件方法中默认就给我们传递了event对象

如下代码所示:

  render() {
      return (
        <div>
          <h2>React Demo</h2>
          <button onClick={this.btnclick}>button</button>
        </div>
      )
    }
    btnclick(e){
      console.log(e);//打印event对象
    }
  }

​ 但是如果我们还想要传递一些其他的参数呢?还记得我们this绑定问题的方案3吗,我们可以使用此方法进行参数的传递,包括event对象(是箭头函数的参数)

看以下需求:我们想要输出一个列表,并且点击单个li标签,打印对象的item和index以及event对象。

  class App extends React.Component {
    constructor(props) {
      super(props),
        this.state = {
          movies: ['A', 'B', 'C', 'D']
        }
      this.btnclick = this.btnclick.bind(this)
    }
    render() {
      return (
        <div>
          <h2>React Demo</h2>
          <ul>
            {
              this.state.movies.map((item, index) => {
                return <li onClick={(e) => {
                  this.liclick(item, index,e)
                }}>{item}</li>
              })
            }
          </ul>
        </div>
      )
    }
    liclick(item, index,e) {
      console.log('li发生了点击', item, index,e);
    }
  }
React 中,`onClick` 事件处理函数直接传参可能会导致意料之外的行为,这是因为事件处理函数的调用方式和 JavaScript 的函数执行机制决定的。如果直接在 JSX 中使用类似 `onClick={this.handleClick(123)}` 的写法,会在组件每次渲染**立即执行该函数**,而不是在点击执行。这通常不是期望的行为,尤其是当该函数用于修改状态或执行副作用,会导致性能问题或逻辑错误。 ### 事件处理函数传参的限制与原因 - 当使用 `<button onClick={this.handleClick(123)}>` 这种方式React 会尝试将 `handleClick(123)` 的返回值作为事件处理函数绑定到 `onClick` 上,而不是将函数本身作为引用传递。如果 `handleClick` 没有返回一个函数,这将导致错误或无效的事件处理程序[^2]。 - 此外,这种方式会在组件渲染立即调用函数,而不是在点击事件发生调用,这可能引发不必要的副作用或错误[^3]。 ### 解决方案 #### 1. 使用箭头函数 可以在 `onClick` 中使用箭头函数来包装调用,这样可以确保函数只在点击执行: ```jsx <button onClick={() => this.handleClick(123)}>Click me</button> ``` 这种方式通过创建一个匿名函数来延迟执行,避免了函数在渲染立即调用的问题。 #### 2. 使用 `bind` 方法 `bind` 方法可以预先绑定函数的参数,并返回一个新的函数,不会在渲染立即执行: ```jsx <button onClick={this.handleClick.bind(this, 123)}>Click me</button> ``` 这种方法避免了在渲染执行函数,并且可以正确传递参数[^2]。 #### 3. 在类组件中使用类属性箭头函数 如果使用类组件,可以将事件处理函数定义为类属性箭头函数,以避免 `this` 指向问题,并结合上述方法之一进行参数传递: ```jsx handleClick = (param) => (event) => { console.log(param); } ``` 然后在 JSX 中使用: ```jsx <button onClick={this.handleClick(123)}>Click me</button> ``` 这样可以确保函数在点击执行,并且能够正确接收参数和事件对象[^3]。 ### 总结 React 中 `onClick` 事件处理函数不能直接传参的主要原因在于函数执行机和返回值的问题。直接传参会导致函数在渲染立即执行,而不是在事件触发执行,这可能引发错误或不必要的副作用。为了解决这个问题,可以使用箭头函数、`bind` 方法或类属性箭头函数来延迟函数的执行并正确传递参数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值