
本文详解如何在 Mui X Data Grid 中通过受控模式(controlled state)实现「展开全部」和「收起全部」按钮的稳定响应,彻底解决 defaultGroupingExpansionDepth 在动态交互后失效的问题。
本文详解如何在 mui x data grid 中通过受控模式(controlled state)实现「展开全部」和「收起全部」按钮的稳定响应,彻底解决 `defaultgroupingexpansiondepth` 在动态交互后失效的问题。
在使用 MUI X Data Grid 构建树形结构(treeData={true})时,开发者常希望通过按钮一键控制所有分组节点的展开/收起状态。虽然官方文档推荐使用 defaultGroupingExpansionDepth(如设为 -1 展开全部、0 收起全部),但该属性仅在组件初始化或重渲染时生效,无法响应运行时的交互变更——一旦用户手动点击某一行展开/收起,后续再点击“展开全部”按钮便不再触发更新,导致 UI 状态与预期脱节。
根本原因在于:defaultGroupingExpansionDepth 是非受控属性(uncontrolled),而树形网格的展开状态实际由内部状态管理。要实现可靠的全量控制,必须采用完全受控模式(controlled mode),即显式接管并同步 groupingExpansionState,并通过 onGroupingExpandedChange 响应用户操作。
✅ 正确实现方式:受控展开状态
以下是一个完整、可复用的解决方案:
import * as React from 'react'; import { DataGridPro, GridGroupingExpansionState } from '@mui/x-data-grid-pro'; import { Stack, Button } from '@mui/material'; // 定义状态常量(语义化提升可读性) const EXPAND_ALL = true; const COLLAPSE_ALL = false; export default function ExpandCollapseAllGrid() { const [expandedState, setExpandedState] = React.useState<GridGroupingExpansionState>(COLLAPSE_ALL); const dataGridApi = React.useRef(null); return ( <Stack spacing={2}> {/* 控制按钮 */} <Stack direction="row" spacing={1} p={1}> <Button variant="contained" size="small" onClick={() => setExpandedState(EXPAND_ALL)} > 展开全部 </Button> <Button variant="outlined" size="small" onClick={() => setExpandedState(COLLAPSE_ALL)} > 收起全部 </Button> </Stack> {/* 受控 DataGridPro */} <DataGridPro treeData rows={rows} // 替换为你的树形数据(需含 `parentId` 字段) columns={columns} apiRef={dataGridApi} // ? 关键:使用 groupingExpansionState 替代 defaultGroupingExpansionDepth groupingExpansionState={expandedState} // ? 关键:监听用户手动展开/收起行为,保持状态同步 onGroupingExpandedChange={(params) => { // 注意:此处不直接设为 params.expanded, // 因为用户单击某节点时,params.expanded 表示该节点新状态, // 而我们维护的是全局统一状态(全展开 / 全收起) // 所以建议:若需支持混合状态(部分展开),应改用 Map 管理各 groupId; // 但本例聚焦「全量控制」,故保持布尔值语义 setExpandedState(params.expanded ? EXPAND_ALL : COLLAPSE_ALL); }} // 其他必要配置 getRowId={(row) => row.id} getTreeDataPath={(row) => row.hierarchy || [row.id]} // 根据数据结构调整 disableSelectionOnClick /> </Stack> ); }
⚠️ 注意事项与最佳实践
- groupingExpansionState 类型:其类型为 GridGroupingExpansionState(即 Boolean | Record
)。上例中使用 boolean 是最简场景;若需更精细控制(例如仅展开某一层级或特定分组),应切换为 Record 并配合 groupId 管理。 - 避免与 defaultGroupingExpansionDepth 混用:二者互斥。启用 groupingExpansionState 后,请务必移除 defaultGroupingExpansionDepth,否则可能引发状态冲突或警告。
- 性能考量:对超大数据集(>5000 行),全量展开可能造成渲染卡顿。建议结合 pagination 或 virtualization(默认启用)确保流畅体验。
- 无障碍支持:MUI X 自动为展开/收起按钮添加 aria-expanded 和键盘导航(Enter/Space 触发),无需额外处理。
✅ 总结
defaultGroupingExpansionDepth 适用于静态初始态,而真正的交互式全量控制必须依赖受控属性 groupingExpansionState + onGroupingExpandedChange。该方案解耦了 UI 操作与内部状态,确保按钮无论在任何当前状态(全收起、部分展开、全展开)下均能可靠生效,是构建专业级树形数据网格的推荐实践。