React递归组件使用Hooks实现一键展开全部子元素功能求助
解决方案:实现点击Expand按钮展开对应父元素下所有层级子元素
问题分析
当前代码里,App组件的expandAll是全局布尔值,没法精准控制单个父元素的全展开;MainAccordion也没处理递归展开所有子元素的逻辑,导致点击Expand按钮达不到预期效果。
修改步骤与代码实现
1. 调整App组件状态与逻辑
把全局的expandAll布尔值改成记录需要全展开项的集合,精准控制单个父元素:
// App.js function App() { // 用Set存储需要全展开的项的title,支持切换展开/取消状态 const [expandedFullItems, setExpandedFullItems] = useState(new Set()); const [data, setData] = useState(manipulateData(originalData)); const handleExpand = (title) => { setExpandedFullItems(prev => { const newSet = new Set(prev); if (newSet.has(title)) { newSet.delete(title); } else { newSet.add(title); } return newSet; }); }; return ( <div className="App"> {data.map((item) => ( <div key={item.title} style={{display:"flex",justifyContent:"space-between"}}> {/* 传递全展开集合,以及当前项是否被标记为全展开 */} <MainAccordion item={item} isFullExpanded={expandedFullItems.has(item.title)} expandedFullItems={expandedFullItems} /> <div style={{padding:"2px", cursor: "pointer"}} onClick={()=>handleExpand(item.title)}> {/* 根据状态切换显示文本 */} {expandedFullItems.has(item.title) ? "Collapse All" : "Expand All"} </div> </div> ))} </div> ); } export default App;
2. 修改MainAccordion组件,支持递归全展开
新增isFullExpanded属性判断当前项是否需要强制全展开,同时将该状态传递给子元素,实现所有层级递归展开:
// MainAccordion.js import { useEffect, useState } from "react"; function MainAccordion({ item, isFullExpanded = false, expandedFullItems }) { const [collapse, setCollapse] = useState(false); const [child, setChild] = useState([]); const handleClick = () => { // 手动点击标题时,覆盖全展开的自动状态 setCollapse(!collapse); }; const getData = (item) => { const arr = Array.from(item.children, function (entry) { return { key: entry[0], value: entry[1] }; }); setChild(arr); }; useEffect(() => { if (item.children){ getData(item); } }, [item.children]); // 监听全展开状态,自动设置折叠状态 useEffect(() => { if (isFullExpanded) { setCollapse(true); } }, [isFullExpanded]); // 判断子项是否需要全展开:当前项全展开,或子项自身被标记为全展开 const getChildFullExpanded = (childItem) => { return isFullExpanded || expandedFullItems.has(childItem.title); }; return ( <div style={{ paddingLeft: 10, cursor: "pointer" }}> <div onClick={handleClick}>{item.title}</div> {collapse && item.children && child.map((childItem) => ( <div key={childItem.key} style={{ paddingLeft: 10 }}> <MainAccordion item={childItem.value} isFullExpanded={getChildFullExpanded(childItem.value)} expandedFullItems={expandedFullItems} /> </div> ))} </div> ); } export default MainAccordion;
关键逻辑说明
- 精准控制单个项:用
Set存储需要全展开的项的title,避免全局布尔值影响所有元素。 - 递归展开:将当前项的
isFullExpanded状态传递给子元素,子元素自动判断是否展开,实现所有层级自动展开。 - 操作优先级:手动点击标题切换折叠状态时,会覆盖全展开的自动状态,保证用户手动操作的优先级。
内容的提问来源于stack exchange,提问作者Gaurav Verma
相关产品推荐
相关产品推荐

