React报错排查:已为列表子元素分配key仍提示“Each child in a list should have a unique 'key' prop”
Fixing "Each child in a list should have a unique 'key' prop" Error (Even With Key Added)
我一眼就看出问题所在了——你把key prop加到了<span>上,但实际上React列表里的每个子元素是那个匿名React Fragment(<>),而不是里面的span。React会把每个<>...</>当作列表中的独立项,它找不到这个项的key,自然就抛出错误了。
Why This Happens
React要求列表中的直接子元素必须拥有唯一的key标识。在你的代码里,content数组的每一项都是一个Fragment(包裹着span和空格),这个Fragment才是React遍历列表时识别的“子元素”,而你把key加在了Fragment内部的span上,React根本看不到这个key。
Solution 1: Use Explicit React.Fragment With Key
把简写的<>...</>换成显式的<React.Fragment>,这样就能给它添加key prop了:
function BertScoreSentence({sentence}: BertScoreSentenceProps) { let content: JSX.Element[] = [] sentence.words.forEach((word) => { content.push( <React.Fragment key={word.id}> <span> {word.text} {bertscores && wordId >= 0 && word.id === bertscores[wordId][3] && isSummaryWord !== visualizeSummary && ( <>(s: {bertscores[wordId][4].toFixed(2)})</> )} </span> </React.Fragment> ) }) return ( <p id={prefix + "" + sentence.id} className={className}> {content} </p> ) }
这样每个列表项(Fragment)都有了唯一的key,React就能正确追踪每个元素的变化了。
Solution 2: Simplify the Structure (Remove Unnecessary Fragment)
如果可以的话,直接去掉Fragment,把 换成CSS的外边距,让span成为列表的直接子元素:
function BertScoreSentence({sentence}: BertScoreSentenceProps) { let content: JSX.Element[] = [] sentence.words.forEach((word) => { content.push( <span key={word.id} style={{marginRight: '0.25em'}}> {word.text} {bertscores && wordId >= 0 && word.id === bertscores[wordId][3] && isSummaryWord !== visualizeSummary && ( <>(s: {bertscores[wordId][4].toFixed(2)})</> )} </span> ) }) return ( <p id={prefix + "" + sentence.id} className={className}> {content} </p> ) }
这个方案更简洁,既解决了key的问题,又避免了不必要的Fragment嵌套。
Quick Notes
- 确保
word.id在当前列表范围内是唯一的,不要出现重复值,否则还是会有key相关的问题。 - 你用
word.id而不是数组索引作为key的做法非常正确,保持这个习惯——索引作为key在列表排序、增删元素时容易导致渲染异常。
内容的提问来源于stack exchange,提问作者Bigabig
相关产品推荐
相关产品推荐

