React嵌套map使用uuidv4仍报key缺失错误如何解决
React map遍历设置key仍触发警告的解决方法
问题现象
在React中通过map遍历渲染列表时,使用uuidv4库生成key值绑定到子元素后,React仍然抛出警告,提示列表子元素必须提供唯一key属性,多次调整代码未解决问题。
原业务代码如下:
// import Sidebar from '../components/Sidebar' import React from 'react' import Navbar from '../components/Navbar'; import ButtonGroup from '../components/ButtonGroup'; import MCQS from '../components/MCQ'; import { Outlet } from 'react-router'; import { v4 as uuidv4 } from 'uuid'; import { useSelector } from 'react-redux'; const C_P_HOME = () => { const { heading } = useSelector(state => state.heading); const { questions } = useSelector(state => state.question); return ( <> <Navbar isContainerTrue={false} /> <div className='grid grid-cols-12 '> <div className="col-span-6 bg-slate-100 grid grid-cols-12 p-8 h-screen items-baseline"> <ButtonGroup /> <Outlet /> </div> <div className="col-span-6 bg-slate-200 h-screen overflow-y-scroll"> <div className="heading select-none"> <h1 className='text-2xl text-center font-bold mt-8'>{heading}</h1> </div> <div className="questions p-8"> { questions.map((q, index) => { return ( <> <h2 className='text-2xl font-semibold' key={uuidv4()}>Q:{(index + 1) + " " + q.heading}</h2> <ol className='list-[lower-roman]' key={uuidv4()}> { q.questions.map((ques, index) => { return ( <> <li className='text-lg ml-16' key={uuidv4()}>{ques}</li> </> ) }) } </ol> </> ) }) } </div> </div> </div> </> ) } export default C_P_HOME;
报错截图:
问题根因
- 遍历返回的根节点是
<></>短语法Fragment时,key必须绑定在最外层的根节点上。代码中把key写在了Fragment内部的h2、ol、li标签上,外层Fragment本身没有key,React无法识别遍历项的唯一标识,因此抛出警告。 - 渲染阶段调用
uuidv4()生成key的写法本身存在性能问题:组件每次重渲染都会生成全新的key值,React会判定所有列表项都发生了变化,无法复用已有DOM节点,导致全量重绘。 <></>短语法形式的Fragment不支持接收包括key在内的任何属性,无法直接绑定key值。
修复方案
- 将map回调中最外层的短语法Fragment替换为显式写法的
React.Fragment,把key绑定在该Fragment上 - 优先使用列表数据本身自带的稳定唯一标识(比如业务id)作为key,没有稳定id时可临时用遍历索引兜底(列表涉及动态增删、排序场景禁止用索引做key),不要在渲染过程中动态生成随机key
修复后的核心遍历代码:
{ questions.map((q, index) => { // 优先取数据自带的唯一id,无id时用索引拼接兜底 const rootKey = q.id ?? `question-group-${index}` return ( <React.Fragment key={rootKey}> <h2 className='text-2xl font-semibold'>Q:{(index + 1) + " " + q.heading}</h2> <ol className='list-[lower-roman]'> { q.questions.map((ques, qIndex) => { const itemKey = ques.id ?? `question-item-${index}-${qIndex}` return ( <React.Fragment key={itemKey}> <li className='text-lg ml-16'>{ques}</li> </React.Fragment> ) }) } </ol> </React.Fragment> ) }) }
提示:如果map返回的根节点是普通DOM元素(比如div、li),直接把key绑定在该DOM元素上即可,不需要额外套Fragment。
内容的提问来源于stack exchange,提问作者Muhammad Kamran
相关产品推荐
相关产品推荐

