【问题标题】:Unique "key" prop in React when returning list with multiple children返回具有多个子项的列表时,React 中的唯一“键”道具
【发布时间】:2016-07-09 01:30:06
【问题描述】:

我必须在一个反应​​组件中呈现多个列表。我通过以下方式创建我的列表:

var jobResources = null;
if (this.state.jobResources) {
  jobResources = _.map(this.state.jobResources, function(jobResource, i) {
    return <ul><li key={i}>{jobResource.resource.name}</li><li key={Math.floor(Math.random()  * (1000 - 100)) + 100}>{translations.resourceType[jobResource.resource.resourceType.name]}</li></ul>
  })
}

说到渲染,我是这样渲染列表的:

  <div>
  <h2>Who is Working on the Project?</h2>
  {this.state.jobResources ? jobResources : null}
  </div>

生成的渲染如下:

<ul data-reactid=".0.2.0.2.1:0">
  <li data-reactid=".0.2.0.2.1:0.$0">Mark Smith</li>
  <li data-reactid=".0.2.0.2.1:0.$270">Hair &amp; MakeUp</li>
</ul>
<ul data-reactid=".0.2.0.2.1:1">
  <li data-reactid=".0.2.0.2.1:1.$1">John Doe</li>
  <li data-reactid=".0.2.0.2.1:1.$377">Photographer</li>
</ul>

在我看来,键是独一无二的。但是,react 给了我以下警告:

警告:数组或迭代器中的每个子元素都应该有一个唯一的“键” 支柱。检查JobDetailPage的渲染方法。看 http://facebook.github.io/react/docs/multiple-components.html#dynamic-children 了解更多信息。

谁能告诉我我犯了什么错误以及解决这个问题的正确方法是什么?

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    没关系,想通了。显然,列表元素也应该有一个键。因此,创建列表的正确方法是:

    var jobResources = null;
    if (this.state.jobResources) {
      jobResources = _.map(this.state.jobResources, function(jobResource) {
        return <ul key={jobResource.id}><li key={jobResource.resource.name}>{jobResource.resource.name}</li><li key={jobResource.resource.resourceType.name}>{translations.resourceType[jobResource.resource.resourceType.name]}</li></ul>
      })
    }
    

    【讨论】:

    • 请注意,简单地使用增量计数器可能会反过来咬你,并导致意想不到的结果。随机密钥也不是很好。如果您在 jobResource 上有某种唯一 ID,最好将其用作 UL 上的键。这样,当您操作列表时,React 将在正确的 UL 上进行操作,而不是重新绘制整个事物,例如删除作业资源时删除底部的。至于li 元素,键可能只是字符串"name""type"
    • @dannyjolie:感谢关于 ul 元素的提醒,我会改变它。但是,对于 li 元素,如果两个资源具有相同的名称(类型太常见而无法用作键)怎么办?这将是一个问题,不是吗?
    • 它们只需要相对于彼此是唯一的。也就是同一个父ul中的两个li元素。不同父母中的元素很可能有相同的键,因为完整的 id 是从父母那里继承的长字符串,并在末尾附加了键。
    • 不客气!我发现key={jobResource.resource.name} 可能有点矫枉过正。此外,在 resource.name 和 resource.resourceType.name 相同的奇怪情况下,它会再次失败。只要您知道总会有两个li 元素,您可以只使用简单的键,我提到的字符串就足够了,您不必验证任何随机数据。
    【解决方案2】:

    我通常这样做

    if (this.state.jobResources) {
      jobResources = _.map(this.state.jobResources, function(jobResource, i) {
        return (
          <ul>
            <li key={i.toString()}>{jobResource.resource.name}</li>
            <li key={`key${i}`}>
              {
                translations.resourceType[
                  jobResource.resource.resourceType.name
                ]
              }
            </li>
          </ul>
        );
      });
    }
    

    【讨论】:

      【解决方案3】:

      这个来自 lodash/underscore 的实用函数很容易解决这个问题:

      key={_.uniqueId()}
      

      【讨论】:

      猜你喜欢
      • 2020-01-24
      • 1970-01-01
      • 2021-10-05
      • 1970-01-01
      • 2021-03-20
      • 2020-03-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多