如何在React AG-Grid数据更新时高效自动调整列宽
AG-Grid React 数据更新后高效自动调整列宽方案
问题场景
我有一个使用AG-Grid的React应用,用户通过下拉框选择筛选值后点击'Get Data',应用会请求后端,后端再调用外部API获取对应数据并在前端渲染表格。需求是:每次重新渲染新数据(即每次点击'Get Data')时,高效自动调整列宽以适配内容。
Grid.jsx 原代码
import { AgGridReact } from 'ag-grid-react'; import { useEffect, useState, useMemo, useRef, useCallback } from 'react'; import 'ag-grid-community/styles/ag-grid.css'; // Core grid CSS, always needed import 'ag-grid-community/styles/ag-theme-alpine.css'; // Optional theme CSS, comment out for custom styling import './Grid.css'; const Grid = ({ gridData }) => { const gridRef = useRef(); // Columns definition const [columnDefs, setColumnDefs] = useState([]); // Data/rows definition const [rowData, setRowData] = useState([]); // Transform grid data into format ag-grid can use const transformGridData = () => { const { columns, rows, cells } = gridData; const transformedColumnDefs = []; const transformedRowData = []; // ... // (omitted) A BUNCH OF LOGIC FOR PARSING THE DATA AND CONVERTING IT INTO AG-GRID's COLS AND ROWS // ... // Set column defs and row data setColumnDefs(transformedColumnDefs); setRowData(transformedRowData); } // Default column style/functionality definition const defaultColDef = useMemo(() => ({ // default col settings }), []); // Update the grid when data given by external API changes useEffect(() => { if (gridData != null) { transformGridData(); } }, [gridData]); return ( <div className="ag-theme-alpine grid-div" style={{ height: 600, marginTop: 50, marginLeft: 17 }}> <AgGridReact ref={gridRef} rowData={rowData} columnDefs={columnDefs} defaultColDef={defaultColDef} /> </div> ) } export default Grid;
已尝试的方法
- 编写自动调整所有列宽的函数:
const autoSizeAll = useCallback(() => { const allColumnIds = []; gridRef.current.columnApi.getColumns().forEach((column) => { allColumnIds.push(column.colId); }); gridRef.current.columnApi.autoSizeColumns(allColumnIds); }, []); - 通过
onFirstDataRendered和onDisplayedColumnsChanged触发该函数,虽生效但应用性能大幅下降; - 在
transformGridData中设置columnDefs和rowData后直接调用autoSizeAll,结果首次点击仅填充数据不调整列宽,再次点击才生效。
高效解决方案
1. 优化自动列宽函数
只针对可见列执行调整,跳过隐藏列减少计算量,同时做安全校验避免空指针:
const autoSizeAll = useCallback(() => { if (!gridRef.current?.columnApi) return; // 获取所有可见列的ID,避免处理隐藏列 const visibleColumnIds = gridRef.current.columnApi.getAllDisplayedColumns().map(column => column.colId); // 第二个参数设为false会同时适配表头内容,按需调整 gridRef.current.columnApi.autoSizeColumns(visibleColumnIds, false); }, []);
2. 选择精准的触发时机
避免使用触发频繁的onDisplayedColumnsChanged,改用以下两个精准事件:
onFirstDataRendered:首次加载数据时触发一次onRowDataChanged:每次rowData更新(即新数据渲染)时触发
在AgGridReact组件中绑定事件:
<AgGridReact ref={gridRef} rowData={rowData} columnDefs={columnDefs} defaultColDef={defaultColDef} onFirstDataRendered={autoSizeAll} onRowDataChanged={autoSizeAll} />
3. 可选:防抖优化(针对频繁数据更新场景)
如果数据可能短时间内多次更新,用防抖函数限制自动调整的执行频率,避免性能浪费:
import { debounce } from 'lodash'; const autoSizeAll = useCallback(debounce(() => { if (!gridRef.current?.columnApi) return; const visibleColumnIds = gridRef.current.columnApi.getAllDisplayedColumns().map(column => column.colId); gridRef.current.columnApi.autoSizeColumns(visibleColumnIds, false); }, 100), []);
方案说明
- 直接调用不生效的原因:React的
setState是异步操作,在transformGridData中设置数据后,网格还未完成新数据加载,此时调用调整函数无法获取新内容的宽度信息。 - 之前性能下降的原因:
onDisplayedColumnsChanged会在列显示/隐藏、列顺序调整等多种场景触发,并非仅在数据更新时,导致调整函数频繁执行。
内容的提问来源于stack exchange,提问作者WesternCreamCheese
相关产品推荐
相关产品推荐

