【问题标题】:Passing keys to children in React.js在 React.js 中将密钥传递给子级
【发布时间】:2015-05-26 17:59:15
【问题描述】:

我正在浏览一个关于 tutsplus 的反应教程,它有点旧,并且代码不像最初编写的那样工作。实际上,我对此完全满意,因为它迫使我更加独立地学习,但是我花了一段时间来解决一个我无法弄清楚的错误。该错误包括无法传递对象键,这会阻止我的程序更新正确对象的状态。

如果您想运行此代码并查看它的实际效果,首先这里是 repo:https://github.com/camerow/react-voteit

我有一个看起来像这样的子组件:

var FeedItem = React.createClass({

  vote: function(newCount) {
    console.log("Voting on: ", this.props, " which should have a key associated.");

    this.props.onVote({
      key: this.props.key,
      title: this.props.title,
      description: this.props.desc,
      voteCount: newCount
    });
  },

  voteUp: function() {
    var count = parseInt(this.props.voteCount, 10);
    var newCount = count + 1;
    this.vote(newCount);
  },

  voteDown: function() {
    var count = parseInt(this.props.voteCount, 10);
    var newCount = count - 1;
    this.vote(newCount);
  },

  render: function() {
    var positiveNegativeClassName = this.props.voteCount >= 0 ?
                                    'badge badge-success' :
                                    'badge badge-danger';
    return (
      <li key={this.props.key} className="list-group-item">
        <span className={positiveNegativeClassName}>{this.props.voteCount}</span>
        <h4>{this.props.title}</h4>
        <span>{this.props.desc}</span>
        <span className="pull-right">
          <button id="up" className="btn btn-sm btn-primary" onClick={this.voteUp}>&uarr;</button>
          <button id="down" className="btn btn-sm btn-primary" onClick={this.voteDown}>&darr;</button>
        </span>
      </li>
    );
  }

});

现在,当有人点击投票按钮时,所需的行为是 FeedItem.vote() 方法将对象发送到主 Feed 组件:

var FeedList = React.createClass({

  render: function() {
    var feedItems = this.props.items;

    return (
      <div className="container">
        <ul className="list-group">

          {feedItems.map(function(item) {
            return <FeedItem key={item.key}
                             title={item.title}
                             desc={item.description}
                             voteCount={item.voteCount}
                             onVote={this.props.onVote} />
          }.bind(this))}
        </ul>
      </div>
    );
  }

});

应该通过父组件的 onVote 函数传递该键:

var Feed = React.createClass({

  getInitialState: function () {
    var FEED_ITEMS = [
      {
        key: 1,
        title: 'JavaScript is fun',
        description: 'Lexical scoping FTW',
        voteCount: 34
      }, {
        key: 2,
        title: 'Realtime data!',
        description: 'Firebase is cool',
        voteCount: 49
      }, {
        key: 3,
        title: 'Coffee makes you awake',
        description: 'Drink responsibly',
        voteCount: 15
      }
    ];
    return {
      items: FEED_ITEMS,
      formDisplayed: false
    }
  },

  onToggleForm: function () {
    this.setState({
      formDisplayed: !this.state.formDisplayed
    });
  },

  onNewItem: function (newItem) {
    var newItems = this.state.items.concat([newItem]);
    // console.log("Creating these items: ", newItems);
    this.setState({
      items: newItems,
      formDisplayed: false,
      key: this.state.items.length
    });
  },

  onVote: function (newItem) {
    // console.log(item);

    var items = _.uniq(this.state.items);
    var index = _.findIndex(items, function (feedItems) {
      // Not getting the correct index.
      console.log("Does ", feedItems.key, " === ", newItem.key, "?");
      return feedItems.key === newItem.key;
    });
    var oldObj = items[index];
    var newItems = _.pull(items, oldObj);
    var newItems = this.state.items.concat([newItem]);
    // newItems.push(item);
    this.setState({
      items: newItems
    });
  },

  render: function () {
    return (
      <div>
        <div className="container">
          <ShowAddButton displayed={this.state.formDisplayed} onToggleForm={this.onToggleForm}/>
        </div>
        <FeedForm displayed={this.state.formDisplayed} onNewItem={this.onNewItem}/>
        <br />
        <br />
        <FeedList items={this.state.items} onVote={this.onVote}/>
      </div>
    );
  }

});

我的逻辑依赖于能够协调 onVote 函数中的键,但是 key prop 没有被正确传递。所以我的问题是,我如何通过这种“单向流”将它们的密钥传递给我的父组件?

注意:请随意指出其他问题或更好的设计决策,或绝对愚蠢。甚至我问错了问题。

期待对这个很酷的框架进行很好的探索。

【问题讨论】:

  • key 在 React 中有特殊的含义。它不能通过this.props.key afaik 提供给组件。您应该为此使用其他道具名称。或者,如果您确实想将该值用作键,请添加一个具有相同属性的附加道具,然后您可以在组件内部访问该道具。见facebook.github.io/react/docs/…
  • 啊,好吧,这帮助很大。我已经阅读了该文档,但对此感到有些困惑。所以澄清一下,我可以定义一个道具key,但它应该看起来像&lt;FeedItem key={item.id} /&gt;?还是我应该完全避免key
  • 仍然收到此警告 Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of FeedList. See https://fb.me/react-warning-keys for more information.,尽管将 key 的所有实例更改为 id 允许我传递该道具。
  • 哦,拥有 object 属性 key 非常好。 prop key 对于 React 来说是特殊的。所以&lt;FeedItem key={item.id} /&gt; 帮助 React 协调组件。然而,FeedItem 的具体实例并不能真正访问key 的值,而且它不应该拥有,因为它与它无关。如果您想将 id 传递给组件以便它可以访问它,请选择不同的 prop 名称。
  • 您还必须设置key&lt;FeedItem key={item.id} id={item.id} /&gt;。这似乎是多余的,但它们有不同的用途:key 用于 React,id 用于您的组件。

标签: javascript properties reactjs


【解决方案1】:

The key prop has a special meaning in React。它不会作为 prop 传递给组件,而是被 React 用于帮助协调集合。如果您知道d3,它的作用类似于selection.data() 的键功能。它允许 React 将前一棵树的元素与下一棵树的元素关联起来。

你有一个 key 很好(如果你传递一个元素数组,你需要一个),但是如果你想将该值传递给组件,你应该使用另一个道具:

<FeedItem key={item.key} id={item.key} ... />

(并在组件内访问this.props.id)。

【讨论】:

  • 谢谢。这解决了我的键控问题,现在我只需要修复我的 onVote 函数中的逻辑。
  • 非常感谢@Felix。顺便说一句,您也可以帮助解决这个问题吗?我想以 React 方式将节点作为属性传递:stackoverflow.com/questions/34879973/…
猜你喜欢
  • 2021-05-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-27
  • 2012-01-23
  • 2020-10-26
  • 1970-01-01
  • 2019-06-06
相关资源
最近更新 更多