Javascript class 实例方法不能与反应中的 onClick 回调事件一起使用

Javascript class instance method does not work with onClick callback event in react

我试图在我的页面上单击按钮时更新我的​​状态变量。 但是我发现我不能使用 react class 组件方法。这是最小的可重现示例。

import React, { Component } from 'react'

export class Name extends Component {
    constructor(){
        super();
        this.state = {
            name : "Farhan Ahmed"
        }
    }
    clickMe() {
        this.setState({
            name:"Ahmed Farhan"
        })
    }

    render() {
        return (
            <div>
                <h1>{this.state.name}</h1>
                <button className="btn btn-success" onClick={this.clickMe}>Change Text</button>
            </div>
        )
    }
}

export default Name

错误:

TypeError: Cannot read properties of undefined (reading 'setState')

但是当我用箭头函数替换它时它对我有用。

我的问题是为什么常规 class 方法在这种情况下不起作用,为什么我需要用箭头函数替换它?

在此处 https://reactjs.org/docs/handling-events.html 找到的文档中解释了此错误以及可能的解决方案。如果您不使用文档引用的实验性“public class 字段语法”,您可以 bind 您的函数,或使用箭头函数:

绑定

onClick={this.clickMe.bind(this)}

箭头函数

onClick={() => this.clickMe()}

这些是最常见的(我个人看到的),但文档也提供了更多解决方案。

编辑

有人指出OP问的是“为什么”,不一定是“我该如何解决?”所以从上面链接的文档:

You have to be careful about the meaning of this in JSX callbacks. In JavaScript, class methods are not bound by default. If you forget to bind this.handleClick and pass it to onClick, this will be undefined when the function is actually called.

This is not React-specific behavior; it is a part of how functions work in JavaScript. Generally, if you refer to a method without () after it, such as onClick={this.handleClick}, you should bind that method.

当您尝试访问 this 关键字而不绑定函数时,this 关键字未定义。因此,您需要在构造函数中绑定该函数或使用箭头函数语法来确保 this 绑定在该函数中。 您可以查看 bind method method and Arrow Function

的文档

按钮未被点击,但组件正在呈现时函数将 运行。

onClick={this.clickMe}  

还有这个;

onClick={() => this.clickMe} 

功能仅在单击按钮时起作用。

读这个:https://beta.reactjs.org/learn/responding-to-events

此问题并非特定于 React,但实际上与 Javascript 的一般工作方式有关。

this 在 javascript 中的功能略有不同。由于 React 是一个 javascript 库,因此 React 中的 this 遵循相同的概念。

在javascript中,this关键字的行为基于函数的调用方式。 this 保存对 javascript 中当前执行上下文的引用。根据调用函数的方式,this 可以引用不同的对象。

  • 如果使用像 obj.functionName() 这样的对象调用函数,那么这将始终 return 对对象的引用

  • 如果函数像 functionName() 这样作为独立函数调用,那么这将 return 引用 window 对象,但如果启用了严格模式, 那么这将 return undefined.

  • 如果一个函数是 class 从回调调用的方法,例如 callback = obj.functionName(); callback(); 那么这将 return 未定义。

现在我们更有兴趣了解我们将 class 函数设置为回调的第三点 onClick

举个例子来理解

使用以下方法考虑 class 矩形

class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
  // Getter
  area() {
    console.log(this);
    return this.calcArea();
  }
  // Method
  calcArea() {
    return this.height * this.width;
  }
}

我们现在就在这里

const square = new Rectangle(10, 10);
square.area()

它给了我们预期的结果

Rectangle {height: 10, width: 10} /* value of this */
100

现在当我们在回调中存储相同的内容并调用回调函数时

callback = square.area;
callback()

这给了我们错误:

undefined  /* value of this */
VM106:9 Uncaught TypeError: Cannot read properties of undefined (reading 'calcArea')
    at area (<anonymous>:9:17)
    at <anonymous>:1:1

如您所见,此值未定义。这是因为 area 方法被重新定义并最终失去它的上下文,即它的 this 关键字引用。你的情况也发生了同样的事情。

解法:

现在尝试使用箭头函数或将相同的函数绑定到 class,您将能够成功调用回调。

使用箭头函数

area = () => {
    console.log(this.width, this.height);
    return this.calcArea();
  }

使用箭头函数的优点是它不会重新定义“this”关键字,从而无需在构造函数中绑定“this”

通过在构造函数中绑定函数

constructor(height, width) {
    this.height = height;
    this.width = width;
    this.area = this.area.bind(this);
  }

现在使用回调调用相同的方法

const square = new Rectangle(10, 10);
callback = square.area;
callback()

会给我们结果

Rectangle {height: 10, width: 10, area: ƒ}
100

这是绑定事件处理程序的好方法,但是为每个事件处理程序重复相同的一组步骤将是一项繁忙的任务。