简体   繁体   English

Javascript 类实例方法不适用于反应中的 onClick 回调事件

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

I was trying to update my state variable when the button is clicked on my page.当单击我的页面上的按钮时,我试图更新我的状态变量。 But I see that I cannot use react class component methods.但是我发现我不能使用 react 类组件方法。 Here is the minimum reproducible example.这是最小的可重现示例。

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

Error :错误 :

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

But when I replace the same with arrow function it works for me.但是当我用箭头函数替换它时,它对我有用。

My question is why didn't regular class method work in this case why do I need to replace the same with arrow function?我的问题是为什么在这种情况下常规类方法不起作用,为什么我需要用箭头函数替换它?

In the docs found here https://reactjs.org/docs/handling-events.html this error is explained, along with possible solutions.在此处找到的文档https://reactjs.org/docs/handling-events.html中解释了此错误以及可能的解决方案。 If you're not using the experimental "public class fields syntax" the docs refer to, you can either bind your function, or use an arrow function:如果您没有使用文档中提到的实验性“公共类字段语法”,您可以bind您的函数,或者使用箭头函数:

With bind带绑定

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

Arrow function箭头函数

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

These are the most common (that I've seen personally), but the docs provide more solutions as well.这些是最常见的(我个人见过),但文档也提供了更多的解决方案。

When you try to access this keyword without binding the function, this keyword is undefined.当您尝试在不绑定函数的情况下访问this关键字时, this关键字未定义。 so, you need to either bind that function in constructor or use an arrow function syntax which ensures this is bound within that function.因此,您需要在构造函数中绑定该函数,或者使用箭头函数语法来确保this绑定在该函数中。 You can check documentation of bind method method and Arrow Function您可以查看绑定方法方法和箭头函数的文档

Button is not clicked, but function will run while the component is rendering.按钮没有被点击,但函数会在组件渲染时运行。

onClick={this.clickMe}  

And this;和这个;

onClick={() => this.clickMe} 

Function only works when the buttons are clicked.功能仅在单击按钮时起作用。

Read this: https://beta.reactjs.org/learn/responding-to-events阅读: https : //beta.reactjs.org/learn/responding-to-events

This problem is not specific to react but actually related to how Javascript works in general.这个问题不是特定于反应的,而是实际上与 Javascript 的一般工作方式有关。

this functions a little differently in javascript. this在 javascript 中的功能略有不同。 Since React is a javascript library, this in React follows the same concept.由于 React 是一个 javascript 库, this React 中的this遵循相同的概念。

In javascript, the behaviour of this keyword is based on how the function is called.在 javascript 中, this关键字的行为基于函数的调用方式。 this holds the reference to current execution context in javascript. this在 javascript 中保存对当前执行上下文的引用。 Depending on how a function is called, this can refer to different objects.根据函数的调用方式, this 可以引用不同的对象。

  • If a function is called using an object like obj.functionName() then this will always return a reference to an object如果使用像obj.functionName()这样的对象调用函数,那么这将始终返回对对象的引用

  • If a function is called as a stand-alone function like functionName() then this will return a reference to window object but if strict mode is enabled, then this will return undefined.如果一个函数像functionName()这样的独立函数被调用,那么这将返回对 window 对象的引用,但如果启用了严格模式,那么这将返回 undefined。

  • If a function is a class method called from a callback like callback = obj.functionName(); callback();如果函数是从回调中调用的类方法,例如callback = obj.functionName(); callback(); callback = obj.functionName(); callback(); then this will return undefined.那么这将返回未定义。

Now we are more interested in knowing about the third point where we are setting our class function to a callback onClick .现在我们更感兴趣的是了解我们将类函数设置为回调onClick的第三点。

Lets understand it with an example让我们通过一个例子来理解它

Consider the class Rectangle with following methods考虑具有以下方法的类 Rectangle

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;
  }
}

Now here when we do现在当我们这样做时

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

It gives us the expected result它给了我们预期的结果

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

Now when we store the same in a call back and call the callback function现在,当我们将相同的内容存储在回调中并调用回调函数时

callback = square.area;
callback()

This gives us error :这给了我们错误:

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

As you can see the value of this is undefined.如您所见, this 的值未定义。 This is because the area method is rescoped and ends up losing its context ie its this keyword reference.这是因为 area 方法被重新定义了范围并最终丢失了它的上下文,即它的this关键字引用。 Same thing is happening in your case as well.你的情况也发生了同样的事情。

Solution :解决方案 :

Now try using an arrow function or binding the same function to the class, you will be able to call the callback successfully.现在尝试使用箭头函数或将相同的函数绑定到类,您将能够成功调用回调。

Using arrow function使用箭头函数

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

Advantage of using arrow function is that it doesn't rescope “this” keyword which eliminates the need to bind “this” in the constructor使用箭头函数的优点是它不会重新定义“this”关键字的范围,从而无需在构造函数中绑定“this”

By binding the function in the constructor通过在构造函数中绑定函数

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

Now calling the same using callback现在使用回调调用相同的

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

will give us the result会给我们结果

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

This is a good approach to bind event handlers but it will be a hectic task to repeat the same set of steps for each event handler.这是绑定事件处理程序的好方法,但为每个事件处理程序重复相同的一组步骤将是一项繁忙的任务。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM