在非全React的TypeScript应用中使用MUI X Data Grid API的优化咨询
关于在非React主导的TS应用中使用MUI X DataGrid的问题解答
1. 更优雅的实现方式
可以从以下几点优化,让代码更简洁可靠:
- 将
setApiRef的调用放到useEffect中,确保apiRef被DataGrid初始化完成后再传递,避免同步调用带来的空值问题 - 移除Grid组件内部的
React.StrictMode(它更适合包裹完整React应用,单个组件使用意义有限,还可能在开发环境触发重复渲染) - 直接在组件内部处理Promise的resolve逻辑,摆脱对外部
setTimeout的依赖
优化后的代码示例:
import * as React from 'react'; import ReactDOM from 'react-dom/client'; import {StyledEngineProvider} from '@mui/material/styles'; import {DataGrid, useGridApiRef} from '@mui/x-data-grid'; import type {GridApi} from '@mui/x-data-grid'; export type ApiRefType = React.MutableRefObject<GridApi | undefined>; type GridProps = { hideFooter: boolean; onApiReady: (ref: ApiRefType) => void; }; const Grid = ({hideFooter, onApiReady}: GridProps): JSX.Element => { const apiRef = useGridApiRef(); React.useEffect(() => { if (apiRef.current) { onApiReady(apiRef); } }, [apiRef, onApiReady]); return ( <StyledEngineProvider injectFirst> <div style={{height: '100%', width: '100%'}}> <DataGrid columns={[]} rows={[]} apiRef={apiRef} hideFooter={hideFooter} /> </div> </StyledEngineProvider> ); }; export const renderGrid = (target: HTMLElement, hideFooter: boolean): Promise<ApiRefType> => { return new Promise((resolve) => { ReactDOM.createRoot(target).render( <Grid hideFooter={hideFooter} onApiReady={resolve} /> ); }); };
2. 为什么需要setTimeout才能获取GridApi
核心原因是React的渲染机制:
- React的渲染是异步批量更新的:调用
ReactDOM.createRoot(target).render()后,组件不会立即完成渲染和挂载,相关DOM更新、组件生命周期钩子会被放到当前事件循环的末尾执行。同步代码中直接获取apiRef时,DataGrid还未完成初始化,apiRef.current仍是空值。 setTimeout(fn, 0)会将回调放到下一个事件循环执行,此时React已完成组件渲染,DataGrid也已把初始化好的GridApi赋值给apiRef.current,因此能拿到有效值。
3. 不修改属性强制DataGrid刷新
完全可以实现,直接调用GridApi提供的refresh()方法即可:
// 假设已通过renderGrid拿到apiRef apiRef.current?.refresh();
该方法会强制DataGrid重新渲染所有行和列,无需修改任何组件属性。如果需要更精细的刷新(比如仅刷新某一行/列),还可以使用apiRef.current?.updateRows()、apiRef.current?.updateColumns()等针对性API。
内容的提问来源于stack exchange,提问作者doberkofler
相关产品推荐
相关产品推荐

