React嵌套JSON渲染为带input的嵌套ul li结构的问题及最佳实践
现有代码问题
- 遍历逻辑错误:调用
map时没有收集遍历返回的节点数组,每次遍历直接覆盖children、sub_children变量值,最终只会保留最后一次遍历的单个子节点,其余子节点全部丢失。 - 层级硬编码:仅手动处理了两层子节点的渲染逻辑,若JSON嵌套层级超过3层就会丢失深层节点,完全没有可扩展性。
- 键值使用错误:列表项的
key属性使用了遍历下标index,若后续列表发生增删、排序操作会触发渲染异常,应该使用节点唯一业务标识id作为key。 - 代码耦合度高:所有逻辑堆叠在
render方法中,难以维护和扩展。
最佳实现方案
这类无限层级的树结构渲染场景,最优解是使用递归渲染逻辑,将单个树节点的渲染逻辑抽离为公共方法,自动识别嵌套层级完成渲染,无需手动处理每一层级:
// 抽离公共递归渲染方法,支持任意层级嵌套 const renderTreeNode = (node) => { return ( <li key={node.id}> <input defaultValue={node.name} /> {/* 存在子节点时递归调用自身渲染子列表 */} {node.children?.length > 0 && ( <ul> {node.children.map(child => renderTreeNode(child))} </ul> )} </li> ) } class Hello extends React.Component { // 静态数据移到组件实例属性,避免每次render重复声明 treeData = {"success":true,"message":"Show All Categories In Tree","data":[{"id":1,"name":"a","slug":"a","order":1,"children":[{"id":2,"name":"comic book","slug":"comic book","order":2,"children":[{"id":3,"name":"Manway Comic Book","slug":"Manway Comic Book","order":3},{"id":4,"name":"Luxury comic book","slug":"Luxury comic book","order":4},{"id":5,"name":"Action comic book","slug":"Action comic book","order":5}]},{"id":6,"name":"textbook","slug":"textbook","order":1,"children":[{"id":7,"name":"commercial","slug":"commercial","order":2},{"id":8,"name":"finance","slug":"finance","order":3},{"id":9,"name":"Computer Science","slug":"Computer Science","order":4}]}]},{"id":10,"name":"electrical","slug":"electrical","order":1,"children":[{"id":11,"name":"TV","slug":"TV","order":2,"children":[{"id":12,"name":"monitor","slug":"monitor","order":3},{"id":13,"name":"Blu-ray","slug":"Blu-ray","order":3}]},{"id":14,"name":"phone","slug":"phone","order":1,"children":[{"id":15,"name":"Huawei","slug":"Huawei","order":3},{"id":16,"name":"iPhone","slug":"iPhone","order":3},{"id":17,"name":"samsung","slug":"samsung","order":3}]}]},{"id":20,"name":"xx","order":1}]}; render() { return <div> <ul> {this.treeData.data.map(node => renderTreeNode(node))} </ul> </div>; } } ReactDOM.render( <Hello name="World" />, document.getElementById('container') );
配套HTML结构保持不变即可:
<script src="https://unpkg.com/react@16/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <div id="container"> </div>
该方案优势:
- 自动适配任意嵌套层级,无需硬编码层级逻辑
- 节点渲染逻辑统一维护,后续需要新增节点编辑、勾选等功能时可直接在
renderTreeNode中修改 - 使用节点唯一
id作为key,避免列表渲染异常 - 代码结构清晰,耦合度低
内容的提问来源于stack exchange,提问作者Jack The Baker
相关产品推荐
相关产品推荐

