You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 18:40:56