React嵌套map渲染组件报key prop缺失/重复错误解决方法
问题根因
Each child in a list should have a unique "key" prop警告的触发原因是:所有通过Array.map()生成的列表直接子元素,都必须传入在当前同级节点下唯一的key属性。之前加key出现重复,大概率是key只使用了单层数组的索引,跨层级时索引值撞重,或是key错加在了嵌套子元素上、没有加在map返回的最外层节点上。
必须添加key的节点
代码一共有三层嵌套map,每一层map返回的最外层元素都需要加key,key只需要保证和同一父节点下的其他兄弟节点不重复即可,不需要全局唯一:
- 第一层:
renderComponentFamilies方法中遍历componentFamilies的map,两个条件分支返回的最外层节点(多组件分支的Grid项、单组件分支的Fragment) - 第二层:
renderComponents方法中遍历components的map,返回的最外层Grid项 - 第三层:
renderCourseRequirements方法中遍历courseList的map,返回的最外层Grid项
注意:单组件分支使用的空标签
<>...</>是简写版Fragment,不支持传入属性,需要改成完整写法React.Fragment才能绑定key。
key赋值方案(避免重复)
优先使用业务自带的唯一标识作为key,渲染稳定性比单纯用数组索引更高,拼接父级标识就能完全避免跨层重复:
- 组件族层:优先用组件族ID,没有的话用
${componentFamily.component_family_name}-${index} - 组件层:优先用组件ID,没有的话用
${component.component_name}-${父级组件族标识}-${index} - 课程层:优先用课程ID,没有的话用
${course}-${父级组件标识}-${index}
修正后完整代码
import React from 'react'; const renderCourseRequirements = (courseList, componentId) => { return ( <Grid> {/* 第三层map:给返回的最外层Grid加key */} {courseList.map((course, index) => { return ( <Grid item xs={12} sm={6} md={4} key={`course-${componentId}-${course}-${index}`} > <Card sx={{ width: 200 }} variant="outlined"> <CardContent> <Typography color="textSecondary" gutterBottom> {course} </Typography> <Checkbox name={course}></Checkbox> </CardContent> </Card> </Grid> ); })} </Grid> ); }; const renderComponents = (components, familyId) => { return ( <Grid justify="center"> {/* 第二层map:给返回的最外层Grid加key */} {components.map((component, index) => { const componentId = `${familyId}-${component.component_name}-${index}`; return ( <Grid item xs={12} sm={6} md={4} key={componentId} > <Card className={classes.root} variant="outlined"> <CardContent> <Typography className={classes.title} color="textSecondary" gutterBottom > {component.component_name} </Typography> <Typography className={classes.pos} color="textSecondary"> Required Number of Courses: {component.required_num_courses} </Typography> {/* 传入当前组件标识给下一层,避免key重复 */} {renderCourseRequirements(component.course_list, componentId)} </CardContent> </Card> </Grid> ); })} </Grid> ); }; const renderComponentFamilies = (componentFamilies) => { return ( <Grid container spacing={4} > {/* 第一层map:给两个分支返回的最外层节点加key */} {componentFamilies.map((componentFamily, index) => { const familyId = `${componentFamily.component_family_name}-${index}`; if (componentFamily.component_list.length > 1) return ( <Grid item xs={12} sm={6} md={4} key={familyId} > <Card className={classes.root} variant="outlined"> <CardContent> <Typography className={classes.title} color="textSecondary" gutterBottom > {componentFamily.component_family_name} </Typography> <Typography className={classes.pos} color="textSecondary"> Required Number of Components :{" "} {componentFamily.required_num_components} </Typography> {renderComponents(componentFamily.component_list, familyId)} </CardContent> </Card> </Grid> ); return ( // 空Fragment改成完整写法以支持key属性 <React.Fragment key={`single-${familyId}`}> <Grid item xs={12} sm={6} md={4}> {renderComponents(componentFamily.component_list, familyId)} </Grid> </React.Fragment> ); })} </Grid> ); };
内容的提问来源于stack exchange,提问作者Jackie Dong
相关产品推荐
相关产品推荐

