反应this.state未定义?

时间:2017-09-01 10:57:26

标签: reactjs

我正在关注Pluralsight的初学者教程,在表单上提交一个值传递给addUser组件方法,我需要将userName推送到this.state.users但是我收到错误

 App.jsx:14 Uncaught TypeError: Cannot read property 'users' of undefined

组件

import React from 'react'
import User from 'user'
import Form from 'form'

class Component extends React.Component {
    constructor() {
        super()
        this.state = {
            users: null
        }
    }
    // This is triggered on form submit in different component
    addUser(userName) { 
        console.log(userName) // correctly gives String
        console.log(this.state) // this is undefined
        console.log(this.state.users) // this is the error
        // and so this code doesn't work
        /*this.setState({
            users: this.state.users.concat(userName)
        })*/
    }
    render() {
        return (
            <div>
            <Form addUser={this.addUser}/>
            </div>
            )
    }
}

export default Component

9 个答案:

答案 0 :(得分:61)

当你调用{this.addUser}时,它会被调用,这里this是你的类(组件)的一个实例,因此它没有给你任何错误,因为addUser方法确实存在你的班级scope, 但当您使用addUser方法时,您正在使用this来更新存在于其中的state 类(组件)的范围,但目前你在addUser方法的范围内,所以它给你一个错误,因为在addUser范围内你没有像州,用户等。 因此,要处理此问题,您需要在调用this方法时绑定addUser。因此,您的方法始终知道this的实例。

因此,代码中的最终更改将如下所示: -

<Form addUser={this.addUser.bind(this)}/>

<小时/> 您可以在构造函数中绑定this,因为它应该是初始化的地方,因为当组件呈现给DOM时,会首先调用构造函数方法。

所以你可以这样做: -

  constructor(props) {
    super(props);
    this.state = {
        users: null
    }
    this.addUser=this.addUser.bind(this);
}

现在您可以像以前一样以正常方式调用它: -

<Form addUser={this.addUser}/>

我希望这会奏效,我向你明确表示。

答案 1 :(得分:9)

@Vinit Raj的方法非常有效-我更喜欢使用箭头函数语法。

<Form addUser={ () => this.addUser() }/>

使用这样的匿名函数,您无需将其绑定到任何地方。

答案 2 :(得分:2)

如果您喜欢使用箭头功能,请执行此操作。箭头函数语法如下所示

addUser = event => { 
    const { value }  = event.target;
    console.log("value", value);
}

要防止在每次渲染或重新渲染时调用此函数,您需要

更改

<Form addUser={this.addUser}/>

收件人

<Form addUser={() => this.addUser()}/>

这样,仅当事件发生/触发时,才调用addUser

答案 3 :(得分:1)

在您的情况下,通过将函数声明为粗箭头函数,可以添加上下文并删除绑定到此的要求。它的工作原理与其他解决方案相同,但使编写和读取过程变得简单得多。只是改变...

 addUser(userName) { 
    console.log(userName) // correctly gives String
    console.log(this.state) // this is undefined
    console.log(this.state.users) // this is the error
    // and so this code doesn't work
    /*this.setState({
        users: this.state.users.concat(userName)
    })*/
}

到...

addUser = (userName) => { 
    console.log(userName) // correctly gives String
    console.log(this.state) // this is undefined
    console.log(this.state.users) // this is the error
    // and so this code doesn't work
    /*this.setState({
        users: this.state.users.concat(userName)
    })*/
}

其他所有内容都可以保持不变。

答案 4 :(得分:0)

我遇到了同样的问题,但是我的问题是尝试在this.state = { ... }调用完成之前访问this.state。正在执行类似this.state = { ...this.function1() }function1 = () => { a: this.state.b }的操作。希望这对某人有帮助

答案 5 :(得分:0)

在函数中简单使用异步

addUser =async (userName) => { console.log(this.state.users) }

这会很好

答案 6 :(得分:0)

我认为其他答案不能很好地解释这一点。基本上,问题在于Javascript的this关键字太疯狂了(MDN非常慷慨地说"behaves a little differently in JavaScript compared to other languages")。

TL; DR的意思是this不一定是定义该方法的类。在this.addUser元素中使用<Form>时,this实际上是Form对象!我不确定为什么React会这样做-我真的不能认为为什么有人会想要这样做,但是很容易验证。只需将console.log(this)放在addUser中,您会发现它是Form的实例。

无论如何,解决方案非常简单-使用箭头功能。箭头函数在定义它们的位置复制this。因此,如果您像其他人所建议的那样在渲染函数中放入一个

<Form addUser={() => this.addUser()}/>

然后,当运行render()时,this将引用Component对象,箭头函数将对其进行复制,然后在运行时将使用该副本。这基本上是该代码的简写(这是人们在使用箭头功能之前曾经做过的事情):

    render() {
        const that = this; // Make a copy of this.
        return (
            <div>
            <Form addUser={function() { return that.addUser; }}/>
            </div>
            )
    }

而且,正如其他人所提到的,每次调用渲染函数时创建一个新函数可能会影响性能,因此最好在其他地方捕获this。我认为这是比其他人建议的更好的方法:

class Component extends React.Component {
    constructor() {
        super()
        this.state = {
            users: null
        }
    }
    // This is triggered on form submit in different component
    addUser = (userName) => { 
        this.setState({
            users: this.state.users.concat(userName)
        })
    }
    render() {
        return (
            <div>
            <Form addUser={this.addUser}/>
            </div>
            )
    }
}

但这是我使用React的第一天,我通常会尽量避免使用像Javascript一样完全吠叫的语言,因此请耐心等待所有这些!

答案 7 :(得分:0)

一个好的模式是将方法绑定到构造函数中的类。 看到 https://reactjs.org/docs/handling-events.html

import React from 'react'
import User from 'user'
import Form from 'form'

class Component extends React.Component {
    constructor() {
        super()
        this.state = {
            users: null
        }
  this.addUser = this.addUser.bind(this); 
  //bind functions which need access to "this"v in the constructor here. 

    }
    // This is triggered on form submit in different component
    addUser(userName) { 
        console.log(userName) // correctly gives String
        console.log(this.state) // this is undefined
        console.log(this.state.users) // this is the error
        // and so this code doesn't work
        /*this.setState({
            users: this.state.users.concat(userName)
        })*/
    }
    render() {
        return (
            <div>
            <Form addUser={this.addUser}/>
            </div>
            )
    }
}

export default Component

答案 8 :(得分:0)

问题就在这种情况下,所以使用

<form onSubmit={(event)=>this.addUser(event)}>
   // Inputs
</form>
addUser(event){
   event.preventDefault()
   // Code this.state 
}