我正在ES6中编写一个简单的组件(使用BabelJS),并函数此。setState不工作。

典型的错误包括

无法读取undefined的属性“setState”

or

这一点。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

当前回答

Bind (this)可以解决这个问题,现在如果你不喜欢使用Bind,我们可以使用另外两种方法来实现这个目标。

1)和传统的方法一样,我们可以在构造函数中使用bind(this),这样当我们使用函数作为JSX回调时,this的上下文就是类本身。

class App1 extends React.Component {
  constructor(props) {
    super(props);
    // If we comment out the following line,
    // we will get run time error said `this` is undefined.
    this.changeColor = this.changeColor.bind(this);
  }

  changeColor(e) {
    e.currentTarget.style.backgroundColor = "#00FF00";
    console.log(this.props);
  }

  render() {
    return (
      <div>
        <button onClick={this.changeColor}> button</button>
      </div>
    );
  }
}

2)如果我们将函数定义为带有箭头函数的类的属性/字段,我们就不需要再使用bind(this)了。

class App2 extends React.Component {
  changeColor = e => {
    e.currentTarget.style.backgroundColor = "#00FF00";
    console.log(this.props);
  };
  render() {
    return (
      <div>
        <button onClick={this.changeColor}> button 1</button>
      </div>
    );
  }
}

3)如果我们使用箭头函数作为JSX回调,我们也不需要使用bind(this)。更进一步,我们可以传递参数。看起来不错,不是吗?但它的缺点是性能问题,详情请参阅ReactJS doco。

class App3 extends React.Component {
  changeColor(e, colorHex) {
    e.currentTarget.style.backgroundColor = colorHex;
    console.log(this.props);
  }
  render() {
    return (
      <div>
        <button onClick={e => this.changeColor(e, "#ff0000")}> button 1</button>
      </div>
    );
  }
}

我已经创建了一个代码依赖来演示这些代码片段,希望它能有所帮助。

其他回答

如果有人能找到这个答案, 下面是一种无需手动绑定所有函数的方法

在构造函数()中:

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

或者在全局变量中创建这个函数。jsx文件

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

并在你的构造函数()调用它如下:

bindAllFunctions({ bindTo: this })

你可以用三种方法来解决这个问题

1.在构造函数本身中绑定事件函数,如下所示

import React from 'react'

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

  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

2.在调用时绑定

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.bind(this)}>Submit</button>
      </div>
    )
  }
}

export default SomeClass

3.通过使用箭头函数

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

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

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

解决方案:

没有显式绑定,绑定方法名可以使用胖箭头函数语法()=>{}来维护此上下文。

import React from 'react'

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

  sendContent = (e) => {
    console.log('sending input content ',this.state.inputContent);
  }

  changeContent = (e) => {
    this.setState({inputContent: e.target.value},()=>{
      console.log('STATE:',this.state);
    })
  } 

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

export default SomeClass

其他的解决方案:

在类构造函数中绑定函数。 在JSX模板转义大括号{}中绑定你的函数 {this.methodName.bind ()}

这一点。在作为onChange道具传递之前,changeContent需要通过this.changeContent.bind(this)绑定到组件实例,否则函数体中的this变量将不会指向组件实例,而是指向窗口。看到函数::绑定。

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

注意绑定一个函数会创建一个新函数。您可以直接在呈现中绑定它,这意味着每次组件呈现时都会创建一个新函数,也可以在构造函数中绑定它,这只会触发一次。

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

vs

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

引用设置在组件实例上,而不是在React上。refs:你需要将react .ref .someref改为this.ref .someref。您还需要将sendContent方法绑定到组件实例,以便该方法引用它。