React.js: 子组件的onClick函数传递给父组件

5
我使用this文章作为示例(React方式),但它对我不起作用。请指出我的错误,因为我无法理解出错的原因。
这是我看到的错误:
Uncaught TypeError: this.props.onClick不是一个函数
这是我的代码:
// PARENT
var SendDocModal = React.createClass({
  getInitialState: function() {
    return {tagList: []};
  },
  render: function() {
    return (
      <div>
        {
          this.state.tagList.map(function(item) {
            return (
              <TagItem nameProp={item.Name} idProp={item.Id} onClick={this.HandleRemove}/>
            )
          })
        }
      </div>
    )
  },
  HandleRemove: function(c) {
    console.log('On REMOVE = ', c);
  }
});

// CHILD
var TagItem = React.createClass({
  render: function() {
    return (
      <span className="react-tagsinput-tag">
        <span>{this.props.nameProp}</span>
        <a className='react-tagsinput-remove' onClick={this.HandleRemove}></a>
      </span>
    )
  },
  HandleRemove: function() {
    this.props.onClick(this);
  }
});

提前感谢!


具体是什么出了问题? - Michael Parker
糟糕!抱歉。我总是遇到一个错误:Uncaught TypeError: this.props.onClick不是一个函数。 - user2787338
2个回答

11

问题在于map回调函数中的this不指向React组件,因此this.HandleRemoveundefined

您可以通过向map传递第二个参数来显式设置this值:

this.state.tagList.map(function() {...}, this);

现在回调函数中的this与回调函数外部的this指向同一个值,即SendDocModal实例。

这与React无关,这是JavaScript的工作原理。有关更多信息和其他解决方案,请参见如何在回调函数中访问正确的`this`上下文?


嗨,Felix。感谢您的回复。我尝试了不使用for循环(只是一个带有硬编码属性的组件),它运行得非常好。但是我不明白如何在我的情况下传递上下文。您能否详细描述一下这个过程? - user2787338
不需要,只需在我的答案中实现解决方案。回调函数的主体保持不变。 - Felix Kling
啊哈,现在我明白了。正确的代码应该是:code {this.state.tagList.map(function(item){ return( <TagItem nameProp={item.Name} idProp={item.Id} onClick={this.HandleRemove}/> ) }, this)} - user2787338
但实际上我并没有理解。如果现在这代表父组件,那么我如何将子组件的“this”传递给父组件,如果现在“this”代表对父组件的引用 -)我完全困惑了。 - user2787338
每个函数都有自己的this。实际上,唯一的问题是您没有将一个函数传递给TagItem,因为map回调中的this并不指向SendDocModal组件。通过正确设置回调函数的thismap回调中的this.HandleRemove现在正确地引用了SendDocModalHandleRemove方法。就是这样。 - Felix Kling
显示剩余3条评论

1
请尝试以下操作:
    var SendDocModal = React.createClass({
        getInitialState: function() {

            var item = {};
            item.Name = 'First';
            item.Id = 123;

            var item2 = {};
            item2.Name = 'Second';
            item2.Id = 123456;
            return {tagList: [item,item2]};
        },

        HandleRemove: function(c){
            console.log('On REMOVE = ', c);
        },

        render: function() {
            return (<div>
                {this.state.tagList.map(function(item){
                    return(
                            <TagItem nameProp={item.Name} idProp={item.Id} key={item.Id} click={this.HandleRemove}/>
                    )}, this)}
                    </div>
            )       
        }

    });
    // CHILD
    var TagItem = React.createClass({

        handleClick: function(nameProp)
        {
            this.props.click(nameProp);
        },


        render: function(){
            return(
                <span className="react-tagsinput-tag" ><span onClick={this.handleClick.bind(this, this.props.nameProp)}>{this.props.nameProp}</span><a className='react-tagsinput-remove' ></a></span>
            )
        }
    }); 

有几个变化:

在tagList映射后添加了'this'。说实话,我不完全确定为什么 - 或许更有经验的程序员可以告诉我们。

为每个TagItem添加了一个键。这是推荐的做法,控制台会提示你应该这样做,以便如果状态发生变化,React可以相应地跟踪每个项目。

点击事件通过props传递。请参见React js - having problems creating a todo list


是的,就像Felix建议的那样,稍微详细一些。非常感谢,我会尝试理解“this”概念,它看起来与Java非常不同... - user2787338

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接