带有onClick事件的React函数在控制台中引发“ TypeError:无法读取未定义的属性'handleDelete'”

时间:2018-07-31 09:59:31

标签: javascript reactjs function

我目前正在尝试从此Youtube Tuorial学习React,但是它们已经过时了(2016年制造)。

预期结果

如果我单击<span> x <span>,则浏览器控制台应显示一个console.log("helloo")

问题:

我当前的问题是,在我编译了我的React代码之后,Chrome开发者控制台日志会抛出以下错误: enter image description here

这是我的文件树:

enter image description here

这是我的index.js文件:

import React from 'react';
import ReactDom from 'react-dom';
import TodoItem from './todoItem'; 

class TodoComponent extends React
  .Component {
    constructor(props) {
      super(props);
      this.state = {
        todos: ["clean up", "walk doggo", "take nap"]
      };
    }
    render() {



      return (
      <div>
        <h1>The todo list:</h1>
        <ul>
          <TodoItem todos={this.state.todos}/>
        </ul>
      </div>);
    }

  }

  ReactDom
  .render(<TodoComponent />, document.querySelector(".todo-wrapper"));

还有我的todoItem.js文件:

import React from 'react';
import ReactDom from 'react-dom';

export default class TodoItem extends React.Component {

  handleDelete(){
    console.log("Hellooo");
  };

  render() {

    let todos = this.props.todos;

    todos = todos.map(function(item, index) {
      return (
      <li>
        <div className="todo-item">
          <span className="item-name">{item}</span>
          <span className="item-remove" onClick={this.handleDelete}> x </span>
        </div>
      </li>);
    });

    return (<React.Fragment>{todos}</React.Fragment>)
  };
}

我一直在使用Stackoverflow,reddit和Google解决此问题,但是出现的大多数结果都在解释为什么在函数内不访问“ this”并通过在构造函数内绑定“ this”来解决。但是,我没有在函数中使用任何此功能,我只想console.log(“ hello”)看看它是否有效。

感谢您的帮助和时间!

5 个答案:

答案 0 :(得分:3)

todos.map(function(item, index) => { });

OR

class App extends React.Component {
  handleDelete() {
    console.log('helo');
  }

  render() {
    let _this = this;
    let todos = this.props.todos;
    
    todos = todos.map(function(item, index) {
      return (
        <li>
          <div className="todo-item">
            <span className="item-name">{item}</span> 
            <span className="item-remove" onClick={_this.handleDelete} > x </span> 
          </div> 
        </li>
      );
    });
    
    return (
      <div>{todos}</div>
    );
  }
}

ReactDOM.render( <App todos={["clean up", "walk doggo", "take nap"]} /> , document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id='root'></div>

答案 1 :(得分:1)

那是我的朋友,因为您传递给地图的回调未“绑定”到您的类TodoItem。为什么是这样 ?这是因为您正在将简单的匿名函数传递给地图。

改为使用箭头语法,以便将传递给.map Array方法的回调自动绑定到render方法内部的this(绑定到组件):

todos = todos.map((item, index) => { return ( <li> <div className="todo-item"> <span className="item-name">{item}</span> <span className="item-remove" onClick={this.handleDelete}> x </span> </div> </li>); });

编辑:当您使用function(){}语法时,可以在地图的回调函数内部进行console.log(this)检查,以确保它等于全局对象

更新:

如果您不想使用箭头功能,可以将其放置在变量中,然后从回调中使用它,例如:

var myComponent = this;

todos = todos.map(function(item, idx) { /*...*/ onClick= 
{myComponent.handleDelete} }

或者在您的组件上声明一个方法,将其绑定,然后将其作为回调函数传递:

class TodoItem extends ... {
    constructor() {
        super();
        this.renderItem = this.renderItem.bind(this);
    }
    renderItem(item, idx) { /*...*/ }

    render() {
        todos = this.state.todos.map(this.renderItem);
    }

答案 2 :(得分:0)

在TodoItem类中

将方法绑定到构造函数中,或使用粗箭头符号。

export default class TodoItem extends React.Component {
 constructor(props){
  super(props)
  this.handleDelete = this.handleDelete.bind(this);
 }
 handleDelete(){
  console.log("Hellooo");
 };
.
.
.
}

或者只是使用粗箭头,如:

<span className="item-remove" onClick={()=>this.handleDelete}> x </span>

答案 3 :(得分:0)

您找到的结果正确。他们引用的this是 this .handleDelete。

调用onClick时,不提供上下文,因为在使用地图时不使用箭头功能。

箭头函数传递上下文,经典的匿名函数不传递上下文。

答案 4 :(得分:-1)

编辑:刚刚发现了实际的问题:在function内包含map会阻止使用this。但是即使将map函数更改为arrow函数,您仍然需要bind()该处理程序或使用arrow函数。

这是一个可行的例子

class App extends React.Component {
  render() {
    let list = [1, 2, 3]; //Can take from props
    list = list.map(item => {
        return (<div onClick={() => console.log(`Item ${item} Clicked`)}>{item}</div>)
    });
    
    return (
      <div>
        {list}
      </div>
    );
  }
}

ReactDOM.render( <App /> , document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id='root'></div>

在此示例中,我希望单击的div显示带有单击数字的警报窗口,因此onClick道具变为onClick={() => this.handleClick(item)}

如果只需要看console.log,我可以向您推荐:      console.log('helooo')}> x

class App extends React.Component {
  render() {
    let list = [1, 2, 3]; //Can take from props
    list = list.map(function(item, index) {
        return (<div onClick={() => console.log('heloo')}>{item}</div>)
    });
    
    return (
      <div>
        {list}
      </div>
    );
  }
}

ReactDOM.render( <App /> , document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id='root'></div>

这永远不会起作用,因为函数是它自己的对象,因此this引用该函数而不是您的类:

class App extends React.Component {
  handleClick = () => {
      console.log('helooo');
  }

  render() {
    let list = [1, 2, 3]; //Can take from props
    list = list.map(function(item, index) {
        return (<div onClick={this.handleClick}>{item}</div>)
    });
    
    return (
      <div>
        {list}
      </div>
    );
  }
}

ReactDOM.render( <App /> , document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id='root'></div>

结论

  1. .bind()您的处理程序,或将其更改为箭头功能。
  2. 您的todo映射需要使用箭头功能来完成。或者,请参阅Rohan Veer的答案,该答案将.this的引用复制到变量中

我只是在这里提供一个可运行的示例