如何在Ag Grid React主行内的详情表格上方添加按钮并优化组件
在Ag Grid React详情网格上方添加按钮及组件优化方案
需求:在Ag Grid React主行展开的详情网格上方添加「New Payment」按钮;同时希望得到提升组件效率、减少潜在错误的建议。
背景:曾尝试自定义详情单元格渲染器但未成功,对官方文档理解有难度,当前组件代码如下:
function CreditorsViewer() { const gridRef = useRef<AgGridReact | null>(null); const defaultColDef = useMemo( () => ({ sortable: true, filter: true, enableRowGroup: true }), []) const detailCellRendererParams = useMemo(() => { return { detailGridOptions: { columnDefs: [ { field: 'amount' }, { field: 'type' }, { field: 'year' }, { field: 'month'}, { field: 'date' }, ], defaultColDef: { flex: 1, sortable: true, filter: true, enableRowGroup: true }, rowSelection: "multiple", rowGroupPanelShow:"always", alwaysShowHorizontalScroll: true, alwaysShowVerticalScroll: true, }, getDetailRowData: (params: GetDetailRowDataParams) => { params.successCallback(params.data.payments) }, }; }, []); const columnsDefs =[ { field: "client", cellRenderer: 'agGroupCellRenderer'}, { field: "contact" }, { field: "debt", valueFormatter: valueFormatterToDH }, { field: "pending", valueFormatter: valueFormatterToDH}, {field: "year"}, {field: "date"}, { field: "transactions" }, ]; const cellClickedListener = useCallback((e: { value: any }) => { console.log('cellClicked', e.value); }, []); return ( <div className="h-full container ag-theme-material"> <AgGridReact defaultColDef={defaultColDef} masterDetail={true} detailRowHeight={300} detailCellRendererParams={detailCellRendererParams} ref={gridRef} rowGroupPanelShow="always" enableRangeSelection={true} enableCharts={true} animateRows={true} rowSelection="multiple" domLayout="autoHeight" alwaysShowHorizontalScroll={true} alwaysShowVerticalScroll={true} rowData={rowData} columnDefs={columnsDefs} onCellClicked={cellClickedListener} /> </div> ); }
一、添加「New Payment」按钮(自定义详情单元格渲染器)
通过自定义详情渲染器组件,将按钮与原详情网格组合,实现需求:
1. 创建自定义详情渲染器
import { AgGridReact } from 'ag-grid-react'; import { IDetailCellRendererParams } from 'ag-grid-community'; // 自定义详情单元格渲染器 const CustomDetailRenderer = (props: IDetailCellRendererParams) => { // 获取当前主行数据 const masterRowData = props.data; // 新增付款按钮点击逻辑 const handleNewPayment = () => { console.log('新增付款,当前客户:', masterRowData.client); // 可扩展为打开新增表单弹窗、调用API等业务逻辑 }; return ( <div style={{ padding: '10px' }}> {/* 新增付款按钮 */} <button onClick={handleNewPayment} style={{ marginBottom: '10px', padding: '6px 12px', cursor: 'pointer' }} > New Payment </button> {/* 原详情网格 */} <AgGridReact {...props.detailGridOptions} rowData={props.detailRowData} domLayout="autoHeight" /> </div> ); };
2. 在主组件中配置使用
修改detailCellRendererParams,指定自定义渲染器:
const detailCellRendererParams = useMemo(() => { return { // 指定自定义详情渲染器 detailCellRenderer: CustomDetailRenderer, detailGridOptions: { columnDefs: [ { field: 'amount' }, { field: 'type' }, { field: 'year' }, { field: 'month'}, { field: 'date' }, ], defaultColDef: { flex: 1, sortable: true, filter: true, enableRowGroup: true }, rowSelection: "multiple", rowGroupPanelShow:"always", }, getDetailRowData: (params) => { params.successCallback(params.data.payments); }, }; }, []);
二、组件效率提升与错误减少建议
1. 强化类型安全,避免any类型
- 替换事件参数的
any类型为Ag Grid官方类型:
import { CellClickedEvent } from 'ag-grid-community'; const cellClickedListener = useCallback((e: CellClickedEvent) => { console.log('cellClicked', e.value); }, []);
- 为数据定义明确的接口:
interface PaymentRow { amount: number; type: string; year: number; month: number; date: string; } interface CreditorRow { client: string; contact: string; debt: number; pending: number; year: number; date: string; transactions: number; payments: PaymentRow[]; } // 为rowData指定类型 const rowData: CreditorRow[] = [];
2. 优化useMemo/useCallback依赖
- 用
useMemo包裹columnsDefs,避免每次渲染创建新数组:
const columnsDefs = useMemo(() => [ { field: "client", cellRenderer: 'agGroupCellRenderer'}, { field: "contact" }, { field: "debt", valueFormatter: valueFormatterToDH }, { field: "pending", valueFormatter: valueFormatterToDH}, {field: "year"}, {field: "date"}, { field: "transactions" }, ], [valueFormatterToDH]); // 若valueFormatterToDH是外部函数,需加入依赖
3. 清理冗余配置与代码
- 移除未使用的
gridRef;若cellClickedListener仅用于调试,可直接删除 - 主网格的
domLayout="autoHeight"与alwaysShowHorizontalScroll可能冲突,根据实际需求调整:如需固定高度,移除domLayout并通过容器类控制高度
4. 增强错误处理
在详情数据加载时添加异常捕获:
getDetailRowData: (params) => { try { const payments = params.data.payments || []; params.successCallback(payments); } catch (error) { console.error('加载详情数据失败:', error); params.successCallback([]); // 失败时返回空数组,避免网格报错 } },
5. 规范数据加载流程
若rowData来自API,用useState+useEffect管理:
const [rowData, setRowData] = useState<CreditorRow[]>([]); useEffect(() => { const fetchData = async () => { const data = await fetchCreditorsData(); // 替换为实际API请求 setRowData(data); }; fetchData(); }, []);
修改后的完整组件代码
import { useMemo, useCallback, useState, useEffect } from 'react'; import { AgGridReact } from 'ag-grid-react'; import { GetDetailRowDataParams, IDetailCellRendererParams, CellClickedEvent, ColDef } from 'ag-grid-community'; import 'ag-grid-community/styles/ag-grid.css'; import 'ag-grid-community/styles/ag-theme-material.css'; // 数据类型定义 interface PaymentRow { amount: number; type: string; year: number; month: number; date: string; } interface CreditorRow { client: string; contact: string; debt: number; pending: number; year: number; date: string; transactions: number; payments: PaymentRow[]; } // 自定义详情渲染器 const CustomDetailRenderer = (props: IDetailCellRendererParams) => { const masterRowData = props.data as CreditorRow; const handleNewPayment = () => { console.log('新增付款,当前客户:', masterRowData.client); // 扩展业务逻辑:打开新增表单弹窗等 }; return ( <div style={{ padding: '10px' }}> <button onClick={handleNewPayment} style={{ marginBottom: '10px', padding: '6px 12px', cursor: 'pointer' }} > New Payment </button> <AgGridReact {...props.detailGridOptions} rowData={props.detailRowData} domLayout="autoHeight" /> </div> ); }; function CreditorsViewer() { const [rowData, setRowData] = useState<CreditorRow[]>([]); const defaultColDef = useMemo<ColDef>(() => ({ sortable: true, filter: true, enableRowGroup: true }), []); const detailCellRendererParams = useMemo(() => { return { detailCellRenderer: CustomDetailRenderer, detailGridOptions: { columnDefs: [ { field: 'amount' }, { field: 'type' }, { field: 'year' }, { field: 'month'}, { field: 'date' }, ], defaultColDef: { flex: 1, sortable: true, filter: true, enableRowGroup: true }, rowSelection: "multiple", rowGroupPanelShow:"always", }, getDetailRowData: (params: GetDetailRowDataParams) => { try { const payments = (params.data as CreditorRow).payments || []; params.successCallback(payments); } catch (error) { console.error('加载详情数据失败:', error); params.successCallback([]); } }, }; }, []); const columnsDefs = useMemo<ColDef[]>(() => [ { field: "client", cellRenderer: 'agGroupCellRenderer'}, { field: "contact" }, { field: "debt", valueFormatter: valueFormatterToDH }, { field: "pending", valueFormatter: valueFormatterToDH}, {field: "year"}, {field: "date"}, { field: "transactions" }, ], [valueFormatterToDH]); const cellClickedListener = useCallback((e: CellClickedEvent) => { console.log('cellClicked', e.value); }, []); // 模拟API数据加载 useEffect(() => { const fetchData = async () => { const mockData: CreditorRow[] = [ { client: "客户A", contact: "张三", debt: 1000, pending: 500, year: 2024, date: "2024-01-01", transactions: 3, payments: [ { amount: 200, type: "转账", year: 2024, month: 1, date: "2024-01-10" }, { amount: 300, type: "现金", year: 2024, month: 2, date: "2024-02-15" } ] } ]; setRowData(mockData); }; fetchData(); }, []); return ( <div className="h-full container ag-theme-material"> <AgGridReact defaultColDef={defaultColDef} masterDetail={true} detailRowHeight={300} detailCellRendererParams={detailCellRendererParams} rowGroupPanelShow="always" enableRangeSelection={true} enableCharts={true} animateRows={true} rowSelection="multiple" rowData={rowData} columnDefs={columnsDefs} onCellClicked={cellClickedListener} /> </div> ); } // 金额格式化函数 function valueFormatterToDH(params: { value: number }) { return `${params.value} DH`; } export default CreditorsViewer;
内容的提问来源于stack exchange,提问作者KM- MK
相关产品推荐
相关产品推荐

