React中MUI DataGrid使用renderCell触发无限更新深度超限报错求助
问题根源
- 核心是每次组件渲染时都会通过
formatColumns生成全新的列配置对象,传递给MUI DataGrid的columns属性每次都是新的引用,MUI检测到columns变化会触发全量重渲染。你点击行触发setRightSlidePlaneOpen更新父组件状态后,当前表格组件会重渲染,再次生成新的columns,触发DataGrid再次重渲染,和状态更新形成循环,导致超出最大更新深度。 - 额外问题:你将JSX元素直接存在
rightSlidePlaneContent状态中,JSX绑定的闭包函数会随着组件重渲染变化,也会引发不必要的重渲染和状态异常。
解决方法
- 用
useMemo缓存格式化后的列配置,只有原始columns变化时才重新生成:
import { useMemo } from 'react'; // 组件内 const formattedColumns = useMemo(() => { return formatColumns(columns); }, [columns]); // DataGrid绑定缓存后的columns <DataGrid columns={formattedColumns} // 其他属性保持不变 />
- 不要在状态中存储JSX元素,改为存储侧边栏配置,渲染时动态生成内容:
父组件修改状态定义:
// 替换原来的rightSlidePlaneContent状态 const [rightSlideConfig, setRightSlideConfig] = useState<{ type: 'view' | 'add' | null; params?: any; isLarge?: boolean; }>({ type: null });
修改打开侧边栏的逻辑:
const openViewPane = (params: GridRowParams, e): void => { setRightSlideConfig({ type: 'view', params, isLarge: true }); setRightSlidePlaneOpen(true); }; const openAddForm = (): void => { setRightSlideConfig({ type: 'add' }); setRightSlidePlaneOpen(true); };
侧边栏渲染时动态生成内容:
// PersistentDrawerRight组件内或者父组件传入content时生成 const getSlideContent = () => { switch(rightSlideConfig.type) { case 'view': return <ViewAccountPane close={closeForm} params={rightSlideConfig.params} />; case 'add': return <AddForm category={'tag'} close={closeAddForm} title={ADD_FORM_TITLE} createFunction={createTag} />; default: return <></>; } }; <PersistentDrawerRight content={getSlideContent()} open={rightSlidePlaneOpen} rspLarge={rightSlideConfig.isLarge || false} />
- 如果单元格内添加了按钮,需要在按钮点击事件中添加
e.stopPropagation()阻止事件冒泡到行,避免触发行点击逻辑。
不使用renderCell添加列按钮的方法
MUI DataGrid提供了专门的操作列类型,不需要手动实现renderCell,官方推荐写法如下:
import { GridActionsCellItem, GridColDef } from '@mui/x-data-grid'; import EditIcon from '@mui/icons-material/Edit'; import DeleteIcon from '@mui/icons-material/Delete'; const columns: GridColDef[] = [ // 其他列配置 { field: 'actions', type: 'actions', // 指定为操作列类型 headerName: '操作', width: 120, getActions: (params) => [ <GridActionsCellItem icon={<EditIcon />} label="编辑" onClick={(e) => { e.stopPropagation(); // 编辑逻辑 }} />, <GridActionsCellItem icon={<DeleteIcon />} label="删除" onClick={(e) => { e.stopPropagation(); // 删除逻辑 }} /> ] } ];
这种写法内置了单元格样式适配,不需要手动处理renderCell的布局问题。
内容的提问来源于stack exchange,提问作者erick
相关产品推荐
相关产品推荐

