React组件数组 - 单击处理程序问题

时间:2017-09-18 19:14:03

标签: javascript reactjs components

使用React 15.6.1 我正在制作一个质量检查论坛,这里是用多个回复呈现单个答案的代码:



import React, { Component } from 'react';
import bindHelper from '../util/bindHelper';

const AnswerStub = (props) => (
  <div className={props.wrapperClass}>
    <div dangerouslySetInnerHTML={{ __html: props.answer.body }} />
    <div className="pull-right">
      <span>{props.answer.author.name}</span><br />
      <span>{props.answer.postDate}</span>
    </div>
  </div>
)

class Answer extends Component {
  constructor(props) {
    super(props);
    this.state = {
      key: props.answer._id,
      replyTo: false,
      replyText: ''
    }
    bindHelper(this);
  }

  _handleReply(event) {
    event.preventDefault();
    console.log(event.target.id);
    console.log(this.state.key);
    this.setState({ replyTo: !this.state.replyTo });
  }

  _handleClear(event) {
    this.setState({ replyText: '' });
  }

  _handleReplyChange(event) {
    this.setState({ replyText: event.target.value });
  }

  _handlePostReply(event) {
    //TODO: dispatch event handler for reply
  }

  render() {
    return (
      <div className="row answer">
        <div className="col-md-1">
          <span className={this.props.answer.accepted ? "glyphicon glyphicon-ok" : ""} />
        </div>
        <AnswerStub wrapperClass="col-md-11" answer={this.props.answer} />
        <div className="comments col-md-12">
          {this.props.answer.replies && this.props.answer.replies.map((reply, i) => <AnswerStub key={i} wrapperClass="comment-single" answer={reply} />)}
        </div>

        <div className="clearfix" />

        {/* REPLY OPTION */}
        <div className="col-md-offset-1 col-md-11">
          <a id={`reply_${this.state.key}`} href="" onClick={this.handleReply.bind(this)}>
            {this.state.replyTo ? "Cancel" : "Post a Reply"}
          </a>
          {this.state.replyTo &&
            <div>
              <textarea className="col-md-11 form-control" rows="3"
                value={this.state.replyText} onChange={this.handleReplyChange} />
              <br />
              <button className="col-md-2 btn btn-default" onClick={this.handleClear}>Clear</button>
              <button className="col-md-2 btn btn-primary pull-right" onClick={this.handlePostReply}>Post</button>
            </div>
          }
        </div>

        <div className="clearfix" />
        <br />

      </div>
    );
  }
}
export default Answer;
&#13;
&#13;
&#13;

我在另一个组件中调用它,如

{this.props.answers && this.props.answers.map((ans,i) => <Answer key={ans._id} answer={ans} />)}

但是当我点击回复时,会打开回复文本框,对于其他每种情况,无论我点击哪个链接,最后一个文本框都会不断切换。

控制台上的示例输出:

59ba431d518a97998d310bd9
reply_59bba3b82219703fb84d07e7
59bba3b82219703fb84d07e7
reply_59ba431d518a97998d310bd9
59bba3b82219703fb84d07e7
reply_59bba3b82219703fb84d07e7
59bba3b82219703fb84d07e7

目标元素是正确的,但它正在访问错误的状态。

不应该将每个答案组件的状态分开吗?我无法弄清楚发生了什么。是的,我是React的初学者!

修改

bindHelper是我编写的用于绑定this引用的辅助函数。

1 个答案:

答案 0 :(得分:1)

好的,问题是在bindHelper中你正在弄乱每个Answer实例的原型。

此时我必须提醒您所有Answer实例共享相同的原型。如果它对您有帮助,您可以找到这样的对象的原型(并且也是100%跨浏览器兼容):

object.constructor.prototype

因此,当每个Answer实例添加一个带有replacement部分的新密钥到原型对象时,您基本上会替换上一次{{1}调用添加的密钥。 }

例如,您拥有第一个bindHelper实例。你打电话给Answer。现在bindHelper(this)(或this.constructor.prototype,它是相同的)有一个新属性this.__proto__,它被绑定到此handleReply实例。

在第二个Answer实例上,当您致电Answer时,您将再次以与之前相同的bindHelper(this)this.constructor.prototype}进行操作。它是相同的,因为this.__proto__的所有实例都共享它。所以,你再次去那里,并将已绑定到先前Answer实例的现有handleReply替换为绑定到Answer实例的新handleReply

所有事情都会发生这种情况,因此,原型上的Answer方法仅绑定到最后一个handleReply实例,从而导致错误。

<强>更新

此处了解Answer的工作原理(抱歉格式错误,我在手机上)

bindHelper

作为一个个人的想法,我发现这个功能非常有限,因为你会发现你可能需要一些名称以一种模式以外的方式开头的方法