React 中自定义组件返回 JSX 数组时正确设置 key 的完整指南

10次阅读

React 中自定义组件返回 JSX 数组时正确设置 key 的完整指南

react 中使用 map 渲染列表时,必须为每个直接子元素(而非其内部元素)提供唯一且稳定的 key 属性;若返回 fragment 或混合节点,key 应作用于最外层容器组件。

你遇到的警告 Each child in a list should have a unique ‘key’ prop 并非因为没写 key,而是因为 key 没有被放在 react 列表渲染的直系子节点上

在你的原始代码中:

words.map((word, index) => {   if (index !== words.length - 1) {     return <>{word} // ;   } else {     return {word};   } })

问题在于:> 是 React.Fragment 的简写,但它本身不可接收 key 属性(空 Fragment 不支持 props)。你把 key={word} 错误地加在了 上,而该 并非 map 返回数组的顶层元素——真正作为 map 结果项的顶层节点是 Fragment。React 要求 key 必须由 map 返回的每个顶层 jsX 元素自身携带,而不是其子元素。

✅ 正确做法:将 key 显式赋予 React.Fragment(或其简写 > 的替代方案——带 key 的 ):

import React from 'react';  function StyleWords({ words, ...props }) {   return words.map((word, index) => {     if (index !== words.length - 1) {       // ✅ key 必须加在 Fragment 上(不能加在 span 上)       return (                    {word} //                 );     } else {       // ✅ 最后一项直接返回带 key 的 span(它本身就是顶层节点)       return {word};     }   }); }

⚠️ 注意事项:

  • 不要用 word 单独作 key:如果数组中存在重复单词(如 [‘hello’, ‘world’, ‘hello’]),key={word} 将导致 key 冲突,触发 React 警告甚至渲染异常。推荐组合索引:key={${word}-${index}}(适用于无动态增删场景);更健壮的方式是确保数据含唯一 ID,或使用 useId(React 18+)生成稳定标识。
  • Fragment 必须显式使用 React.Fragment 或 :空标签 …> 不支持 key,这是常见误区。
  • 避免在条件分支中混用不同根节点类型:本例中前几项返回 Fragment、最后一项返回 span,虽可行,但可优化为统一结构,提升可维护性:
// ✅ 更清晰统一的写法(推荐) function StyleWords({ words, separator = ' // ' }) {   return words.map((word, index) => (            {word}       {index < words.length - 1 && {separator}}        )); }

这样既保证 key 正确绑定,又语义清晰、易于扩展分隔符逻辑。记住核心原则:key 属于列表项的容器,不是内容元素

text=ZqhQzanResources