反应-未捕获的TypeError:无法读取未定义的属性'setState'


315

我收到以下错误

未捕获的TypeError:无法读取未定义的属性'setState'

即使在构造函数中绑定了delta之后。

class Counter extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            count : 1
        };

        this.delta.bind(this);
    }

    delta() {
        this.setState({
            count : this.state.count++
        });
    }

    render() {
        return (
            <div>
                <h1>{this.state.count}</h1>
                <button onClick={this.delta}>+</button>
            </div>
        );
    }
}

4
在ES6中,可以使用箭头函数进行函数声明来解决此问题。
Tal

^这应该是正确的答案
Jordec

我将响应功能更改为ES6,并且hurrey正常运行。
Ashwani Garg

Answers:


447

这是由于this.delta不受约束this

为了this.delta = this.delta.bind(this)在构造函数中绑定集:

constructor(props) {
    super(props);

    this.state = {
        count : 1
    };

    this.delta = this.delta.bind(this);
}

当前,您正在调用绑定。但是bind返回一个绑定函数。您需要将函数设置为其绑定值。


186
如果ES6类的方法没有适当的词法this绑定,然后甚至不公开直接在其定义上绑定其上下文的语法,那到底有什么意义呢?
AgmLauncher

1
我明白您的意思,但是如果我在componentWillMount()中编写代码,那么我将如何绑定
suresh pareek

1
@sureshpareek一旦将函数绑定到构造函数中,则从任何生命周期挂钩调用函数时都应将其绑定。
Levi Fuller

4
来自android / java世界,我感到困惑
都铎王朝

3
@AgmLauncher使用Lambda函数隐式绑定此函数。如果您将代码定义deltadelta = () => { return this.setState({ count: this.state.count++ }); };也可以。这里解释: hackernoon.com/...
K.罗达

144

ES7 +(ES2016)中,可以使用实验性函数bind语法运算符::进行绑定。它是一种语法糖,将与Davin Tryon的回答相同。

然后您可以重写this.delta = this.delta.bind(this);this.delta = ::this.delta;


对于ES6 +(ES2015),您还可以使用ES6 + 箭头功能=>)进行使用this

delta = () => {
    this.setState({
        count : this.state.count + 1
    });
}

为什么呢 从Mozilla文档中:

在使用箭头功能之前,每个新功能都定义了自己的值。事实证明,使用面向对象的编程风格很烦人。

箭头函数捕获封闭上下文的值[...]


3
好的文章对此进行了详细描述:reactkungfu.com/2015/07/…–
Edo

除了语法之外,使用一个相比另一个还有什么好处?
杰里米D

2
绑定语法更简洁,因为您可以保留方法的常规范围。
Fabien Sa

绑定语法不属于ES2016或ES2017。
Felix Kling

2
@stackoverflow应该增加向任何答案添加赏金的功能。
加布

29

ES5和ES6类之间的上下文有所不同。因此,实现之间也会有一些差异。

这是ES5版本:

var Counter = React.createClass({
    getInitialState: function() { return { count : 1 }; },
    delta: function() {
        this.setState({
            count : this.state.count++
        });
    },
    render: function() {
        return (
            <div>
              <h1>{this.state.count}</h1>
              <button onClick={this.delta}>+</button>
            </div>
            );
    }
});

这是ES6版本:

class Counter extends React.Component {
    constructor(props) {
        super(props);
        this.state = { count : 1 };
    }

    delta() {
        this.setState({
            count : this.state.count++
        });
    }

    render() {
        return (
            <div>
              <h1>{this.state.count}</h1>
              <button onClick={this.delta.bind(this)}>+</button>
            </div>
            );
    }
}

请注意,除了类实现的语法差异之外,事件处理程序绑定也有所不同。

在ES5版本中,

              <button onClick={this.delta}>+</button>

在ES6版本中,它是:

              <button onClick={this.delta.bind(this)}>+</button>

在JSX中使用箭头功能或绑定是一种不好的做法。stackoverflow.com/questions/36677733/…
法比恩·萨

24

在React中使用ES6代码时,请始终使用箭头功能,因为上下文会自动与其绑定

用这个:

(videos) => {
    this.setState({ videos: videos });
    console.log(this.state.videos);
};

代替:

function(videos) {
    this.setState({ videos: videos });
    console.log(this.state.videos);
};

2
如果使用箭头函数并且参数变量键变量相同,则我建议将其用作 this.setState({videos});
jayeshkv

这就是为我做的。我是Node的新手,并且axios模块的文档与react和setState不兼容
dabobert

20

您不必绑定任何东西,只需使用Arrow函数,如下所示:

class Counter extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            count: 1
        };

    }
    //ARROW FUNCTION
    delta = () => {
        this.setState({
            count: this.state.count++
        });
    }

    render() {
        return (
            <div>
                <h1>{this.state.count}</h1>
                <button onClick={this.delta}>+</button>
            </div>
        );
    }
}

那行得通,有什么区别,为什么?
里达·雷扎格

4
带有箭头功能的作用域是从上下文继承的。对于常规函数,这始终指的是最接近的函数,而对于箭头函数,此问题已消除,并且您无需再次编写var that = this。@RezzagRidha
加博·鲁伊斯

1
截至2019年,这就是要走的路(Y)
MH

6

您还可以使用:

<button onClick={()=>this.delta()}>+</button>

要么:

<button onClick={event=>this.delta(event)}>+</button>

如果您要传递一些参数。


在JSX中使用箭头功能是一种不好的做法
Gabe

5

您需要将此绑定到构造函数,并记住对构造函数的更改需要重新启动服务器。否则,您将遇到相同的错误。


1
因为我没有重新启动服务器,所以正在拔头发。
kurtcorbett

5

您必须将方法与“ this”(默认对象)绑定。因此,无论您使用什么函数,都可以将其绑定到构造函数中。

constructor(props) {
    super(props);
    this.state = { checked:false };

    this.handleChecked = this.handleChecked.bind(this);
}

handleChecked(){
    this.setState({
        checked: !(this.state.checked)
    })
}

render(){
    var msg;

    if(this.state.checked){
        msg = 'checked'
    }
    else{
        msg = 'not checked'
    }

    return (
        <div>               
            <input type='checkbox' defaultChecked = {this.state.checked} onChange = {this.handleChecked} />
            <h3>This is {msg}</h3>
        </div>
    );

4

此错误可以通过多种方法解决-

  • 如果您使用的是ES5语法,那么根据React js文档,您必须使用bind方法。

    上面的例子是这样的:

    this.delta = this.delta.bind(this)

  • 如果您使用的是ES6语法,则无需使用bind方法,可以使用以下方法进行操作:

    delta=()=>{ this.setState({ count : this.state.count++ }); }


2

此问题有两种解决方案:

第一种解决方案是向您的组件添加一个构造函数,并像下面这样绑定您的函数:

constructor(props) {
        super(props);

        ...

        this.delta = this.delta.bind(this);
    }

这样做:

this.delta = this.delta.bind(this); 

代替这个:

this.delta.bind(this);

第二种解决方案是改为使用箭头函数:

delta = () => {
       this.setState({
           count : this.state.count++
      });
   }

实际上,箭头函数绑定它自己的this。箭头函数按词汇表述bind其上下文,因此this实际上是指原始上下文

有关绑定函数的更多信息:

绑定函数 了解JavaScript绑定()

有关箭头功能的更多信息:

Javascript ES6-箭头函数和词汇 this


1

您必须将新事件与关键字绑定,如下所述。

class Counter extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            count : 1
        };

        this.delta = this.delta.bind(this);
    }

    delta() {
        this.setState({
            count : this.state.count++
        });
    }

    render() {
        return (
            <div>
                <h1>{this.state.count}</h1>
                <button onClick={this.delta}>+</button>
            </div>
        );
      }
    }

1

新增中

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

将解决问题。当我们尝试调用ES6类的函数时会出现此错误,因此我们需要绑定该方法。


1

箭头功能可以使您的生活更加轻松,避免绑定关键字。像这样:

 delta = () => {
       this.setState({
           count : this.state.count++
      });
   }

0

尽管这个问题已经有了解决方案,但我只想分享我的观点以使其得到解决,希望它能对您有所帮助:

/* 
 * The root cause is method doesn't in the App's context 
 * so that it can't access other attributes of "this".
 * Below are few ways to define App's method property
 */
class App extends React.Component {
  constructor() {
     this.sayHi = 'hello';
     // create method inside constructor, context = this
     this.method = ()=> {  console.log(this.sayHi) };

     // bind method1 in constructor into context 'this'
     this.method1 = this.method.bind(this)
  }

  // method1 was defined here
  method1() {
      console.log(this.sayHi);
  }

  // create method property by arrow function. I recommend this.
  method2 = () => {
      console.log(this.sayHi);
  }
   render() {
   //....
   }
}

0
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Hello World</title>

    <script src="https://unpkg.com/react@0.14.8/dist/react.min.js"></script>
    <script src="https://unpkg.com/react-dom@0.14.8/dist/react-dom.min.js"></script>
    <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>

  </head>
  <body>
  <div id="root"></div>
    <script type="text/babel">

        class App extends React.Component{

            constructor(props){
                super(props);
                this.state = {
                    counter : 0,
                    isToggle: false
                }
            this.onEventHandler = this.onEventHandler.bind(this);   
            }

            increment = ()=>{
                this.setState({counter:this.state.counter + 1});
            }

            decrement= ()=>{
                if(this.state.counter > 0 ){
                this.setState({counter:this.state.counter - 1});    
                }else{
                this.setState({counter:0});             
                }
            }
            // Either do it as onEventHandler = () => {} with binding with this  // object. 
            onEventHandler(){
                this.setState({isToggle:!this.state.isToggle})
                alert('Hello');
            }


            render(){
                return(
                    <div>
                        <button onClick={this.increment}> Increment </button>
                        <button onClick={this.decrement}> Decrement </button>
                        {this.state.counter}
                        <button onClick={this.onEventHandler}> {this.state.isToggle ? 'Hi':'Ajay'} </button>

                    </div>
                    )
            }
        }
        ReactDOM.render(
        <App/>,
        document.getElementById('root'),
      );
    </script>
  </body>
  </html>

0

只需将绑定语句从必须更改的内容更改为=> this.delta = this.delta.bind(this);


0
  1. 检查状态 检查状态是否创建特定属性

this.state = {
            name: "",
            email: ""
            }
            
           
            
this.setState(() => ({ 
             comments: comments          //comments not available in state
             })) 

2. 检查(this) 是否在任何函数(即handleChange)内执行setState,检查该函数是否绑定到this或该函数应为arrow function。

##将其绑定到以下功能的3种方法##

//3 ways for binding this to the below function

handleNameChange(e) {  
     this.setState(() => ({ name }))
    }
    
// 1.Bind while callling function
      onChange={this.handleNameChange.bind(this)}
      
      
//2.make it as arrow function
     handleNameChange((e)=> {  
     this.setState(() => ({ name }))
     })
    
//3.Bind in constuctor 

constructor(props) {
        super(props)
        this.state = {
            name: "",
            email: ""
        }
        this.handleNameChange = this.handleNameChange.bind(this)
        }


0

如果您使用的是ES5语法,则需要正确绑定它

this.delta = this.delta.bind(this)

如果你正在使用ES6及以上的,你可以使用箭头功能,那么你就需要使用bind()的

delta = () => {
    // do something
  }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.