React 警告:flattenChildren(...):遇到两个具有相同密钥的孩子

Posted

技术标签:

【中文标题】React 警告:flattenChildren(...):遇到两个具有相同密钥的孩子【英文标题】:React Warning: flattenChildren(...): Encountered two children with the same key 【发布时间】:2017-06-01 20:55:24 【问题描述】:

谁能解释一下如何解决这个错误

警告:flattenChildren(...): 遇到两个相同的孩子 关键

我在下面复制了我的代码,但由于某种原因 CodePen 没有显示错误。

var FilterOptions = React.createClass(
changeOption: function(type, e) 
var val = e.target.value;
this.props.changeOption(val, type);
,

render: function() 

return (
  <div className="filter-options">
    <div className="filter-option">
      <select id="product" name="Product" value=this.props.product onChange=this.changeOption.bind(this, 'product')>
      <option value=''>Product</option>
      this.props.productOptions.map(function(option) 
        return (<option key=option  value=option>option</option>)
      )
      </select>
  </div>
  </div>
 );
 
 );

Codepen

作为第二个问题,我很确定我的重置应该重置选择框的值,但这也不起作用,只是重置呈现的结果 - 不确定这是否与第一个问题有关?

非常感谢任何帮助

【问题讨论】:

您确定this.props.productOptions 具有唯一值吗?如果是这样,那么您确定此代码给出了错误而不是其他地方吗? @MartinMazzaDawson 不,所有选择菜单中都有一些重复的值 - 确切的错误都是这样的 - bundle.js:9899 警告:flattenChildren(...):遇到两个孩子相同键,1:$prod3。子键必须是唯一的;当两个孩子共享一个密钥时,只会使用第一个孩子。 如果您将key 更改为索引值而不是option,错误会消失吗? 错误是不言自明的,你不应该有两个具有相同键的项目。您正在寻求什么样的帮助? 【参考方案1】:

使用索引作为键不是一个好主意。键是 React 唯一用来识别 DOM 元素的东西。如果您将一个项目推送到列表中或删除中间的某个项目会发生什么?如果 key 和之前一样,React 假定 DOM 元素代表和之前一样的组件。但这不再是真的。来自:https://medium.com/@robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318

最好使用您要映射的每个项目的唯一字符串作为键。 &lt;option key=value.id&gt; 之类的东西,或者如果某个键不存在,则通过执行&lt;option key=value.name + value.description&gt; 之类的东西来创建一个唯一标识符。

【讨论】:

Arrg 但是如果 props 对象中没有任何独特的东西怎么办?就我而言,我有一排有 5 个复选框。为数组中的每个条目生成复选框。但它们并没有什么独特之处...... @Kokodoko 在这种情况下最好使用不可变数据(或者至少尽量不要系统地改变您的复选框),并使用对象的哈希作为键。这是区分点、复选框等对象并创建唯一键的唯一方法。【参考方案2】:

将索引添加为值解决了这个问题。感谢@azium 的建议。

  <select id="product" name="Product" value=this.props.product onChange=this.changeOption.bind(this, 'product')>
      <option value=''>Product</option>
      this.props.productOptions.map(function(option, value) 
        return (<option key=value  value=option>option</option>)
      )
      </select>

【讨论】:

这似乎与 React 希望你做的事情有悖常理,但它确实有效。我之前使用了一个唯一的 ID 字段,我花了一个小时才弄清楚这个解决方案。我仍然不知道为什么它会在 ID 绝对唯一的简单映射数组上呈现具有相同键的多个项目。 这是一个糟糕的答案。以后如果你map()另一个数组,并且索引相同,你会得到一个键冲突。【参考方案3】:

我非常喜欢通过将索引与某个常量值组合来使用键,而不是使用key=value.name + value.description

key='some-constant-value'+index

这是因为我可以知道它是为哪个组件传递密钥。例如。 &lt;ComponentA key='compoent-a-'+i /&gt;。另外,我采用这种方法是因为简单的 html 约定匹配我们给id="my-some-of-the-id" 或其他东西。

所以,即使你想使用名称和描述作为键,你也可以这样使用:

key='some-constant-'+value.name+'-'+value.description

这只是一个意见。不过,我在编写 props 值时遵循 html 约定。

【讨论】:

【参考方案4】:

实际上您需要为每个孩子指定一个唯一的键,因此您需要创建另一个键,例如,如果您从数据库中获取数据,则创建一个新列,例如 (id),然后添加该列的值到您的 div 或您作为键循环的内容

var FilterOptions = React.createClass(
changeOption: function(type, e) 
var val = e.target.value;
this.props.changeOption(val, type);
,

render: function() 

return (
  <div className="filter-options">
    <div className="filter-option">
      <select id="product" name="Product" value=this.props.product onChange=this.changeOption.bind(this, 'product')>
      <option value=''>Product</option>
      this.props.productOptions && this.props.productOptions.map(function(option) 
        return (<option key=option.id  value=option>option</option>)
      )
      </select>
  </div>
  </div>
 );
 
 );

我希望这对将来的任何人都有帮助。

【讨论】:

以上是关于React 警告:flattenChildren(...):遇到两个具有相同密钥的孩子的主要内容,如果未能解决你的问题,请参考以下文章

警告:flattenChildren (...) 遇到两个具有相同键的孩子 - 反应原生

React 警告:函数作为 React 子级无效

React & Redux tslint 警告

react-select:如何解决“警告:道具`id`不匹配”

“‘React’在定义之前就被使用了。”警告

你如何配置 Webpack 以清除生产缩小的 React 警告?