【问题标题】:React this.state is undefined?反应 this.state 是未定义的?
【发布时间】:2017-09-01 10:57:25
【问题描述】:

我正在学习 Pluralsight 的初学者教程,在表单提交时将值传递给 addUser 组件方法,我需要将用户名推送到 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

【问题讨论】:

  • addUser = (userName) =&gt; {
  • @Andrew 为什么要这样写?
  • 用于自动绑定此函数中的上下文,但这里看起来不正确。
  • 我知道 :p 只是我更喜欢 bind。它很脏但有效..
  • @IvanTopić 将此行放入构造函数中:this. addUser = this. addUser.bind(this) 该语法是属性初始化器语法,这是 实验性 语法,您需要为此使用 babel 插件。跨度>

标签: reactjs


【解决方案1】:

当您调用 {this.addUser} 时,它会被调用,这里 this 是您的类(组件)的一个实例,因此它不会给您任何错误,因为您的类 scope 中确实存在 addUser 方法, 但是当您使用addUser 方法时,您正在使用this 更新存在于中的state 类(组件)的范围,但目前您在addUser 方法的范围内,因此它会给您一个错误,因为在addUser 范围内您没有任何状态、用户等。 所以要处理这个问题,你需要在调用addUser方法的时候绑定this。这样你的方法总是知道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}/>

我希望这会奏效,并且我已经向你说清楚了。

【讨论】:

  • 为什么构造函数和渲染函数能正确理解“this”,但 addUser 却认为它是未定义的?
  • @Loreno,函数是对象并且有自己的范围。使用 bind(this) 或函数表达式(lambda 表达式),我们将函数的范围定义为当前类。我希望这会有所帮助。
  • @Loreno Component(包含其他 HTML 元素的已定义组件)称为 contstructorrender,但组件中的 Form 元素是试图调用的addUser,但是,它不包含对该函数的引用。其他人建议使用代码{ () =&gt; this.addUser() },因为该代码在render函数范围内调用addUser,意思是this指的是Component而不是Form
【解决方案2】:

@Vinit Raj 的方法非常有效——尽管我更喜欢像这样使用箭头函数语法。

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

使用这样的匿名函数,你不需要在任何地方绑定它。

【讨论】:

  • 这将在每个渲染上创建一个新函数,这会影响性能。由于该函数不接受任何参数,因此最好像这样声明它:&lt;Form addUser={ this.addUser }/&gt; 并使用 addUser = () =&gt; ... 这样的箭头函数声明添加用户
  • 整个“这可能会导致性能问题”的比喻是一匹死马。对其进行基准测试以证明它,而不是散布技术喋喋不休。你如何证明在this 上调用bind 比创建新的箭头函数更快?事实是,它可能太小以至于无法在基准测试中检测到。两者之间的任何可能偏差都远远超过了网络延迟等因素的不确定性。使用更具可读性的那个,直到 它实际上成为代码中可衡量的瓶颈
【解决方案3】:

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

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

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

改变

<Form addUser={this.addUser}/>

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

只有在事件发生/触发时才会调用 addUser

【讨论】:

  • 它不会在每次渲染时都被调用,除非你像&lt;Form addUser={this.addUser()}/&gt;这样内联调用
【解决方案4】:

我遇到了同样的问题,但我的问题是在 this.state = { ... } 调用完成之前尝试访问 this.state。正在做类似this.state = { ...this.function1() }function1 = () =&gt; { a: this.state.b } 的事情。希望这可以帮助某人

【讨论】:

    【解决方案5】:

    在您的情况下,通过将函数声明为胖箭头函数,您可以添加上下文并删除绑定到 this 的要求。这与其他解决方案的工作原理相同,但使写入和读取都变得更加简单。换一个吧……

     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)
        })*/
    }
    

    其他一切都可以保持不变。

    【讨论】:

      【解决方案6】:

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

      TL;DR 是 this 不一定是定义该方法的类。当您在 &lt;Form&gt; 元素中使用 this.addUser 时,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】:

        一个好的模式是在构造函数中将方法绑定到类。 看 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】:

          问题就在这个上下文中,所以使用

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

          【讨论】:

            【解决方案9】:

            在函数中简单地使用异步

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

            这会很好用

            【讨论】:

              猜你喜欢
              • 2023-03-31
              • 2018-05-09
              • 2017-08-21
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2018-01-24
              相关资源
              最近更新 更多