You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React递归Accordion组件报列表子元素需唯一key prop的解决方法

报错原因

这个报错是React列表渲染的通用规则触发的:所有通过数组遍历(一般是Array.prototype.map)生成的元素,必须给遍历返回的最外层根节点传入同层级唯一的key属性,用于虚拟DOM的差异比对优化。
你的代码里有两个和key相关的错误:

  • 你加在最外层<div className={'tabs'}>上的key={explorer.label}完全无效,这个元素不在任何数组遍历的循环体内,React不会把它识别为列表项的key
  • 真正触发报错的位置是explorer.children.map的遍历返回值:你返回的最外层节点是<React.Fragment>,这个节点没有设置key属性,React遍历生成列表项时找不到唯一标识就会抛出这个错误。
修复步骤
  • 第一步:删除最外层tabs div上多余的无效key属性
  • 第二步:给map遍历返回的React.Fragment加上同层级唯一的key。如果你的数据源每个节点有全局唯一的id字段,优先用id当key;如果没有id,且同层级下label不会重复,可以临时用child.label当key
  • 注意:给React.Fragment传key属性时不能用简写语法<></>,必须使用完整的<React.Fragment>标签写法,你当前的写法是支持传key的,直接加属性即可。
修复后完整代码
import React, { useState, useCallback } from 'react'
import { Container, Grid } from '@material-ui/core'
import './styles.css'


function Accordion({ explorer }) { // 修正了原组件名的拼写错误,原拼写Accodian少了个r,不影响运行但不符合常规命名
    const [ expand, setExpand ] = useState(false)
    const handleExpand = useCallback(() => {
        setExpand(prevState => !prevState)
    })
    if (explorer.children) {
        return (
            // 已删除此处原有的无效key
            <div style={{ width: '100%' }} className={'tabs'}>
                {explorer.children ? (
                    <>
                        <div className='tab' onClick={handleExpand}>
                            <label className={ expand ? 'tab-label-expanded' : 'tab-label' }>
                                {explorer.label}
                            </label>
                        </div>
                        {expand ? (
                            <Container className='tab-content'>
                                <Grid container spacing={1}>
                                    {explorer.children.map(child => {
                                        return (
                                            // 给遍历的最外层Fragment加上唯一key
                                            <React.Fragment key={child.id ?? child.label}>
                                                {Array.isArray(child.children) ? (
                                                    <Accordion explorer={child}/>
                                                ) : (
                                                    <Grid item xs={12} sm={6} md={6} lg={4} xl={3}>
                                                        <li>
                                                            <b>{child.label}</b>{' '}: {child.value}
                                                        </li>
                                                    </Grid>
                                                )}
                                            </React.Fragment>
                                        )
                                    })}
                                </Grid>
                            </Container>
                        ) : null}
                    </>
                ) : null}
            </div>
        )
    } else {
        return <div style={{ paddingLeft: '20px' }}>{explorer.label}</div>
    }
}

export default Accordion

补充说明:如果你的业务场景下同层级可能出现label重复的情况,一定要提前给每个数据节点加全局唯一的id字段,用id作为key可以完全避免列表渲染错位、状态混乱的问题。

内容的提问来源于stack exchange,提问作者KARTHIKEYAN.A

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 06:54:32