React.js - 无法读取未定义的属性

IT技术 javascript reactjs
2021-05-22 06:48:55

我正在制作非常简单的react应用程序。然而,当我尝试通过 onChange 事件调用父(实际上是祖父)组件的方法时,我不断收到Uncaught TypeError: Cannot read property 'props' of undefined.

这是触发事件的组件/表单(因此在绑定的父组件上调用方法......是的,当我通过props从父组件传递它时,我在方法上使用了 .bound(this) 。)。

class MonthsTable extends Component {
  handleChangeOnMonth(e){ 
    this.props.setMonth(e.target.id, e.target.value); // here the method is not found, causing error.
  }
  render(){
    console.log(this.props.setMonth) // here the method is present alright
    return (<form>
      {this.props.months.map((e, i) =>
         <input
          type='number'
          id={i} 
          key={i} // yes I know, bad habit, but in this case it doesn't matter
          value={this.props.months[i]}
          onChange={this.handleChangeOnMonth} />)}
    </form>)
  }
}

这是我如何将方法作为来自大多数父(祖父)组件的props传递。

<Months setMonth={this.setMonth.bind(this)} />

这是我如何在父级(方法所有者和方法调用者之间的组件)中将方法作为props传递

<MonthsTable setMonth={this.props.setMonth} />

最后传递给你首先看到的组件(MonthsTable)。无论是否相关,最终(大多数子)组件都会根据是否正常工作的 if 语句显示(可能以某种方式相关,我不知道)。

问题是... 为什么 (setMonth) 方法在 (handleChangeOnMonth) 方法中“不可见”。

感谢您的任何建议。

3个回答

这里的实际问题是this您的handleChangeOnMonth函数中没有定义上下文这是由于 javascript 处理函数上下文的方式引起的,基本上在调用函数时,如果您不是直接从对象调用它们,并且它们没有被绑定,它们将没有定义的上下文,并且由于您正在传递函数作为输入组件的参数,它失去了上下文。

解决这个问题最简单的方法是绑定函数,我建议你在构造函数中绑定函数,像这样:

class MonthsTable extends Component {
  constructor(props, context){
    super(props, context);
    this.handleChangeOnMonth = this.handleChangeOnMonth.bind(this);
  }
  handleChangeOnMonth(e){ 
    this.props.setMonth(e.target.id, e.target.value);
  }
  render(){
    return (<form>
      {this.props.months.map((e, i) =>
         <input
          type='number'
          id={i} 
          key={i} 
          value={this.props.months[i]}
          onChange={this.handleChangeOnMonth} />)}
    </form>)
  }
}

或者,如果您使用装饰器,您可以使用该core-decorators包以更优雅的方式执行此操作:

import {autobind} from "core-decorators"

@autobind
class MonthsTable extends Component {     
  handleChangeOnMonth(e){ 
    this.props.setMonth(e.target.id, e.target.value);
  }
  render(){
    return (<form>
      {this.props.months.map((e, i) =>
         <input
          type='number'
          id={i} 
          key={i} 
          value={this.props.months[i]}
          onChange={this.handleChangeOnMonth} />)}
    </form>)
  }
}

您必须将提供给 onChange 的函数绑定到当前上下文。您可以在类的构造函数中绑定它,也可以将它直接绑定到 onChange(),但这不是一个好习惯。

class MonthsTable extends Component {
  constructor(props){
    super(props);
    this.handleChangeOnMonth = this.handleChangeOnMonth.bind(this);
  }
  handleChangeOnMonth(e){ 
    this.props.setMonth(e.target.id, e.target.value); // here the method is not found, causing error.
  }
  render(){
    console.log(this.props.setMonth) // here the method is present alright
    return (<form>
      {this.props.months.map((e, i) =>
         <input
          type='number'
          id={i} 
          key={i} // yes I know, bad habit, but in this case it doesn't matter
          value={this.props.months[i]}
          onChange={this.handleChangeOnMonth.bind(this)} />)}
    </form>)
  }
}

如果您不想绑定您编写的每个函数。您可以使用 ES6 箭头函数。这是有效的,因为箭头函数没有自己的this,所以它们继承了类的this. 您可以在此处阅读有关词法作用域(幕后机制)的更多信息这个解决方案实际上出现在文档中

handleChangeOnMonth = (e) => { 
  this.props.setMonth(e.target.id, e.target.value);
}