React.js与两个拥有相同密钥的孩子混淆了。

时间:2015-04-01 03:47:57

标签: javascript reactjs

我正在使用反应在页面上安装两个相同的组件,

var SelectBox = React.createClass({
  getDefaultProps: function() {
    return {
      value: []
    };
  },
  getInitialState: function() {
    return {checked: this.props.value,count: 1};
  },
  handleClick: function() {
    var opt = this.state.checked;
    opt.push({id: this.state.count, name: this.state.count});
    this.setState({checked: opt, count: this.state.count + 1});
  },
  render: function() {
    var that = this;
    var options = this.state.checked.map(item => <option key={'checked-' + that.props.name + item.id} value={item.id}>{item.name}</option>);
    return (
      <div>
        <select multiple={true}>
          {options}
        </select>
        <button type="button" onClick={this.handleClick}>add</button>
      </div>
    );
  }
});
React.render(
  <SelectBox name='one'/>,
  document.getElementById('one')
);
React.render(
  <SelectBox name='two'/>,
  document.getElementById('two')
);

然后点击&#39; one&#39;的按钮,好吧,但是当我点击&#39; two&#39;的一些按钮时,&#39; one&#39; 39;在&#39;两个&#39;中出现,为什么?这让我感到困惑。控制台显示:

Warning: flattenChildren(...): Encountered two children with the same key, `.$checked-two1`. Child keys must be unique; when two children share a key, only the first child will be used.

但只是做一些改变

var a = [{id: 5, name: 5}];
React.render(
  <SelectBox name='one' value={a}/>,
  document.getElementById('one')
);

它正常工作。 发生了什么?有什么不对或是它的错误吗?

3 个答案:

答案 0 :(得分:4)

哦,我发现真正的原因,getDefaultProps被调用一次并缓存,getDefaultProps()返回的任何复杂对象将在实例之间共享,而不是复制,因此所有SelectBox组件都没有显式值prop传递将在状态中共享相同的已检查数组引用。 在这种情况下,我应该写:

  getInitialState: function() {
    var tmp = this.props.value.concat();
    return {checked: tmp, count: 1};
  },

答案 1 :(得分:2)

不,这里没有错误,你要渲染两次组件的相同实例,这意味着&#39;组件&#39;共享相同的状态但是当你传递不同的道具时,组件现在会有两个状态来跟踪。

答案 2 :(得分:1)

当我在列表样式的反应组件中设置键时,似乎出现了这个问题,并且传递给键的id不是唯一的,正如错误描述所示。

例如 2个列表项的密钥为1.

这通常是由于设置您的唯一ID的逻辑错误。

对于我的示例,我在应用程序状态中使用了redux存储,并且我将项目的id设置为items.length + 1这是不正确的。

这导致我two children with the same key error以上。要解决此问题,我会将每个新项目的ID设置为列表中itemsAdded的数量。

它与数据库中的密钥类似,其中id保持递增,因此您可以在数据库中没有任何项目,因为它们全部删除,但是下一个项目的ID可能是1000。