React中如何通过ID切换嵌套数组对象的isExpanded属性并更新状态
React 递归切换嵌套数组对象的isExpanded状态并更新组件状态
要实现点击ID切换嵌套数组中对应对象的isExpanded属性,核心是遵循React状态不可变的原则,通过递归遍历并复制数据结构来修改目标属性,再更新组件状态。
完整实现代码
假设你的组件中使用useState管理这份嵌套数据:
import { useState } from 'react'; // 定义数据类型(TypeScript可选) type OutlineItem = { id: string; title: string; isExpanded: boolean; children: OutlineItem[]; }; const MyComponent = () => { // 初始数据 const initialData: OutlineItem[] = [ { id: '1', title: 'Introduction to Programming', isExpanded: true, children: [ { id: '1.1', title: 'What is programming?', isExpanded: false, children: [ { id: '1.1.1', title: 'What is programming?', isExpanded: false, children: [] }, { id: '1.1.2', title: 'What is programming?', isExpanded: false, children: [] }, ], }, { id: '1.2', title: 'Programming languages', isExpanded: false, children: [ { id: '1.2.1', title: 'Programming languages', isExpanded: false, children: [] }, { id: '1.2.2', title: 'Programming languages', isExpanded: false, children: [] }, ], }, ], }, ]; const [outlineData, setOutlineData] = useState<OutlineItem[]>(initialData); const handleExpandOutlineItem = (id: string) => { // 递归函数:遍历并修改目标项的isExpanded const toggleItemExpanded = (items: OutlineItem[]): OutlineItem[] => { return items.map(item => { // 找到目标ID的项,复制并切换isExpanded if (item.id === id) { return { ...item, isExpanded: !item.isExpanded }; } // 未找到则递归处理子节点,保留其他属性不变 return { ...item, children: toggleItemExpanded(item.children) }; }); }; // 使用函数式更新确保拿到最新状态 setOutlineData(prevData => toggleItemExpanded(prevData)); }; // 渲染逻辑示例 const renderItems = (items: OutlineItem[]) => { return items.map(item => ( <div key={item.id}> <button onClick={() => handleExpandOutlineItem(item.id)}> {item.isExpanded ? '▼' : '▶'} {item.title} </button> {item.isExpanded && item.children.length > 0 && ( <div style={{ marginLeft: 20 }}> {renderItems(item.children)} </div> )} </div> )); }; return <div>{renderItems(outlineData)}</div>; }; export default MyComponent;
关键说明
- 不可变性处理:每次修改都通过扩展运算符
{...item}复制原对象,避免直接修改原状态数据,符合React的状态更新规范。 - 递归遍历:
toggleItemExpanded函数会遍历每一层的children,不管嵌套深度多少,都能找到目标ID的项并切换状态。 - 函数式状态更新:调用
setOutlineData时传入函数,确保使用最新的prevData进行修改,避免因闭包导致的状态过期问题。 - 渲染联动:状态更新后,组件会自动重新渲染,根据
isExpanded的值控制子节点的显示/隐藏。
内容的提问来源于stack exchange,提问作者Egor
相关产品推荐
相关产品推荐

