无法在事件处理程序中访问React实例(this)

我正在用ES6(使用BabelJS)编写一个简单的组件,并且功能this.setState无法正常工作。

典型的错误包括类似

无法读取未定义的属性“ setState”

要么

this.setState不是一个函数

你知道为什么吗?这是代码:

import React from 'react'

class SomeClass extends React.Component {
  constructor(props) {
    super(props)
    this.state = {inputContent: 'startValue'}
  }

  sendContent(e) {
    console.log('sending input content '+React.findDOMNode(React.refs.someref).value)
  }

  changeContent(e) {
    this.setState({inputContent: e.target.value})
  } 

  render() {
    return (
      <div>
        <h4>The input form is here:</h4>
        Title: 
        <input type="text" ref="someref" value={this.inputContent} 
          onChange={this.changeContent} /> 
        <button onClick={this.sendContent}>Submit</button>
      </div>
    )
  }
}

export default SomeClass
番长猴子古一2020/03/10 22:22:25

亚力山大·柯森伯格(Alexandre Kirszenberg)是对的,但是要注意的另一件重要事情是放置绑定的位置。我已经被这种情况困扰了好几天(可能是因为我是一个初学者),但是与其他人不同,我知道bind(我已经申请过),所以我无法理解为什么我仍然会遇到这种情况错误。事实证明我绑定的顺序错误。

另一个可能是我在“ this.state”中调用函数的事实,该函数不知道绑定,因为它恰好位于绑定线上方,

以下是我所拥有的(顺便说一下,这是我的第一篇文章,但是我认为这非常重要,因为在其他任何地方都找不到解决方案):

constructor(props){
    super(props);

       productArray=//some array

    this.state={ 
        // Create an Array  which will hold components to be displayed
        proListing:productArray.map(product=>{return(<ProRow dele={this.this.popRow()} prodName={product.name} prodPrice={product.price}/>)})
    }

    this.popRow=this.popRow.bind(this);//This was the Issue, This line //should be kept above "this.state"
猿老丝2020/03/10 22:22:25

您正在使用ES6,因此函数不会自动绑定到“此”上下文。您必须手动将函数绑定到上下文。

constructor(props) {
  super(props);
  this.changeContent = this.changeContent.bind(this);
}
Harry泡芙2020/03/10 22:22:25

这个问题发生,因为this.changeContentonClick={this.sendContent}没有绑定到这个组件的实例。

还有另一种解决方案(除了使用bind()的构造函数())使用共享周围的代码相同词法范围ES6的箭头功能,并保持这个,所以你可以改变在渲染(你的代码)是:

render() {
    return (

        <input type="text"
          onChange={ () => this.changeContent() } /> 

        <button onClick={ () => this.sendContent() }>Submit</button>

    )
  }
StafanTony2020/03/10 22:22:25

这个问题在react15.0之后发生,该事件处理程序没有自动绑定到组件。因此,无论何时调用事件处理程序,都必须手动将其绑定到组件。


解决问题有几种方法。但是您需要知道哪种方法最好,为什么?通常,我们建议在类构造函数中绑定函数或使用箭头函数。

// method 1: use a arrow function
    class ComponentA extends React.Component {
      eventHandler = () => {
        console.log(this)
      }
      render() {
        return ( 
        <ChildComponent onClick={this.eventHandler} /> 
        );
      }

// method 2: Bind your functions in the class constructor.
    class ComponentA extends React.Component {
      constructor(props) {
        super(props);
        this.eventHandler = this.eventHandler.bind(this);
      }
      render() {
        return ( 
        <ChildComponent onClick={this.eventHandler} /> 
        );
      }

组件每次渲染时,这两种方法将不会创建新函数。因此我们的ChildComponent不会因为新功能道具的更改而重新渲染,否则可能会产生性能问题。

阿飞古一A2020/03/10 22:22:25

您的函数需要绑定才能在事件处理程序中使用状态或道具

在ES5中,仅将事件处理函数绑定到构造函数中,而不直接绑定到render中。如果您确实直接在render中绑定,那么每次您的组件渲染并重新渲染时,它都会创建一个新函数。因此,您应该始终将其绑定到构造函数中

this.sendContent = this.sendContent.bind(this)

在ES6中,使用箭头功能

使用箭头功能时,无需绑定,也可以避免与范围相关的问题

sendContent = (event) => {

}
小宇宙路易2020/03/10 22:22:25

如果要使绑定保持构造函数语法,则可以使用proposal-bind-operator并转换代码,如下所示:

constructor() {
  this.changeContent = ::this.changeContent;
}

代替 :

constructor() {
  this.changeContent = this.changeContent.bind(this);
}

简单得多,不需要bind(this)fatArrow

西门Sam2020/03/10 22:22:24

我的建议是使用箭头函数作为属性

class SomeClass extends React.Component {
  handleClick = () => {
    console.log(this); // the React Component instance
  }
  render() {
    return (
      <button onClick={this.handleClick}></button>
    );
  }
}

并且不要将箭头功能用作

class SomeClass extends React.Component {
      handleClick(){
        console.log(this); // the React Component instance
      }
      render() {
        return (
          <button onClick={()=>{this.handleClick}}></button>
        );
      }
    }

因为第二种方法实际上将在每个渲染调用中生成新函数,实际上这意味着新版本的props指针,而不是如果您以后在意性能,则可以使用React.PureComponent或在React.Component中, 您可以覆盖shouldComponentUpdate(nextProps,nextState)并在道具到达时进行浅层检查

阿飞米亚2020/03/10 22:22:24

如果有人能得到这个答案,这是一种绑定所有功能的方法,而无需手动绑定它们

在constructor()中:

for (let member of Object.getOwnPropertyNames(Object.getPrototypeOf(this))) {
    this[member] = this[member].bind(this)
}

或在global.jsx文件中创建此函数

export function bindAllFunctions({ bindTo: dis }) {
for (let member of Object.getOwnPropertyNames(Object.getPrototypeOf(dis))) {
    dis[member] = dis[member].bind(dis)
    }
}

并在您的Constructor()中将其调用为:

bindAllFunctions({ bindTo: this })
JinJin乐2020/03/10 22:22:24

我们必须对bind函数进行操作,this以获取类中函数的实例。像这样

<button onClick={this.sendContent.bind(this)}>Submit</button>

这种方式this.state将是有效的对象。

蛋蛋GO2020/03/10 22:22:22

Morhaus是正确的,但是没有可以解决bind

您可以将箭头函数类属性提案一起使用

class SomeClass extends React.Component {
  changeContent = (e) => {
    this.setState({inputContent: e.target.value})
  } 

  render() {
    return <input type="text" onChange={this.changeContent} />;
  }
}

因为arrow函数是在构造函数的范围内声明的,并且因为arrow函数是this在其声明范围内进行维护的,所以它们都可以工作。缺点是这些将不是原型上的函数,它们将与每个组件一起重新创建。但是,这不会带来太大的负面影响,因为会bind导致相同的结果。

Davaid阳光小卤蛋2020/03/10 22:22:22

this.changeContentthis.changeContent.bind(this)在作为onChangeprop 传递之前,需要先通过绑定到组件实例,否则this函数主体中的变量将不会引用组件实例,而是指向window参见Function :: bind

当使用React.createClass而不是ES6类时,组件上定义的每个非生命周期方法都会自动绑定到组件实例。请参阅自动绑定

请注意,绑定功能会创建一个新功能。您可以将其直接绑定到render中,这意味着每次渲染该组件时都会创建一个新函数,或者将其绑定到构造函数中,后者只会触发一次。

constructor() {
  this.changeContent = this.changeContent.bind(this);
}

render() {
  return <input onChange={this.changeContent.bind(this)} />;
}

引用是在组件实例上设置的,而不是在组件实例上设置的React.refs:您需要更改React.refs.somerefthis.refs.someref您还需要将sendContent方法绑定到组件实例,以便对其进行this引用。