【问题标题】:Why does 'key' not propagate to react elements in map of {children} elements?为什么“键”不传播到 {children} 元素映射中的反应元素?
【发布时间】:2020-07-14 17:52:57
【问题描述】:

我正在实现一个组件,使用户可以更轻松地向页面添加多个项目。由于我有几种类型的项目可以由用户添加,因此我认为使用带有“children”参数的单个组件将是最有用的。

但是,当映射到子元素时,该实现遇到了“key”参数的问题。

function ExpandableSet({
   startingSet,
   itemTitle,
   children
})
{

   const largestId = useMemo(() => {
      return startingSet.reduce((largestId, item) =>
         if (item.id > largestId){
            return item.id
         }
         return largestId
      }, 0)
   }, [])

   const [itemCount, setItemCount] = useState(largestId + 1);
   const [items, setItems] = useState(startingSet);

   return(
      <div className="expandable-set">
         { items.map( item =>
            <div className="expanded-item" id={item['key']} key={item['key']}> { children } </div>
         )}
      </div>
      <button onClick={() =>
         {
            items.push({"key" : itemCount});
            setItemCount(itemCount + 1);
         }
      }>
         Add {itemTitle}
      </button>
   )
}

ExpandableSet 使用时是这样使用的:

...
<div className="container-for-expandable-set">
   <ExpandableSet
      startingSet={[]}
      itemTitle="Some item I want a lot of" />
      <SomeItem opts=opts />
   </ExpandableSet>
</div>
...

因为我不知道会有多少SomeItem 元素,所以没有办法在父级传递键而不在那里管理状态。这会破坏ExpandableSet 组件的目的(也许这是正确的答案?)

当这是输出时,我看到标准的each child in a list should have a unique 'key' prop 错误。

HTML 输出

...
<div class="expandable-set">
 <div class="expanded-item" id="0">
  <div class="child-template-passed">
   ...
  </div>
 </div>
 <div class="expanded-item" id="1">
  <div class="child-template-passed">
   ...
  </div>
 </div>
</div>
...

为什么我仍然看到 key 错误?

【问题讨论】:

  • 键是唯一的吗?
  • 是的——我在 div 中添加了“id”,以便确保它们适当地递增。
  • 子元素是否在组件数组中传递?
  • 请附上startingSet的例子
  • @MosheSommers,不太清楚你在问什么,但我添加了一个代码块来显示组件的使用方式。

标签: reactjs children react-props react-component


【解决方案1】:

您从一个可能有 N 个元素的起始集合开始,每个元素可能具有从零开始的任何 ID,然后是一个从零开始的计数器。

因此,如果我通过页面上的按钮将一个项目添加到集合中,它的 ID 将为零。但是,如果起始集中的一个项目的 ID 已经为零怎么办?您现在在集合中有一个重复的 ID。

你需要在起始集中找到最大的ID,并用这个ID加一作为itemCount的初始值。

const largestID = useMemo(() => {
  return startingSet.reduce((largestID, item) => {
    if (item.key > largestID) {
      return item.key
    }
    return largestID
  }, 0)
}, [startingSet])

const [items, setItems] = useState(startingSet);
const [itemCount, setItemCount] = useState(largestID + 1);

【讨论】:

  • 基本上是一个索引,但是只要将id/key分配给元素,它就会坚持数据并单调增加,并且元素永远不会删除,这可能没问题。
  • @DrewReese,是的 - id 存储在数组中,如果删除任何项目,所有其他项目都保留其 id。计数器只会上升。
猜你喜欢
  • 2023-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-31
  • 2018-03-06
  • 1970-01-01
  • 2015-10-27
  • 2010-12-04
相关资源
最近更新 更多