为什么 'key' 不传播到 {children} 元素映射中的反应元素?
Why does 'key' not propagate to react elements in map of {children} elements?
我正在实现一个组件,使用户可以更轻松地向页面添加多个项目。因为我有几种类型的项目可以由用户添加,所以我认为拥有一个带有“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
错误?
您从一个可能有 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);
我正在实现一个组件,使用户可以更轻松地向页面添加多个项目。因为我有几种类型的项目可以由用户添加,所以我认为拥有一个带有“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
错误?
您从一个可能有 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);