합계 및 요약행 (Summary Row)

AXDGProps의 summary 설정으로 상단 또는 하단에 사용자 정의 요약 셀을 표시하는 방법을 학습합니다.

#summary#AXDGSummaryColumn#itemRender#colSpan
검토일: 2026-08-17
GitHub
import { Divider, Radio } from 'antd';
import { useEffect, useState } from 'react';
import * as React from 'react';
import { AXDataGrid, AXDGColumn, AXDGProps } from '@axboot/datagrid';
import { useContainerSize } from '../hooks/useContainerSize';
import DataGridContainer from '../components/DataGridContainer';

interface Props {}

interface IListItem {
  id?: string;
  class?: string;
  title?: string;
  writer?: string;
  createAt?: string;
}

const list = Array.from(Array(50)).map((v, i) => ({
  values: {
    id: `ID_${i}`,
    class: `class_${Math.floor(i / 5)}`,
    title: `title_${i}`,
    writer: `writer_${i}`,
    createAt: `2022-09-08`,
  },
}));

const summary1: AXDGProps<any>['summary'] = {
  position: 'top',
  columns: [
    {
      columnIndex: 0,
      align: 'center',
      itemRender: ({ data }) => {
        return <>합계</>;
      },
    },
    {
      columnIndex: 2,
      itemRender: ({ data }) => {
        return <>Summary</>;
      },
    },
    {
      columnIndex: 3,
      colSpan: 2,
      itemRender: ({ data }) => {
        return <>COUNT : {data.length}</>;
      },
    },
  ],
};

const summary2: AXDGProps<any>['summary'] = {
  position: 'bottom',
  columns: [
    {
      columnIndex: 0,
      align: 'center',
      itemRender: ({ data }) => {
        return <>합계</>;
      },
    },
    {
      columnIndex: 2,
      colSpan: 2,
      align: 'right',
      itemRender: ({ data }) => {
        return <>Summary</>;
      },
    },
    {
      columnIndex: 5,
      colSpan: 2,
      itemRender: ({ data }) => {
        return <>Summary</>;
      },
    },
  ],
};

function SummaryExample(props: Props) {
  const [summaryKey, setSummaryKey] = useState('summary1');
  const [summary, setSummary] = useState<AXDGProps<any>['summary']>();
  const [columns, setColumns] = React.useState<AXDGColumn<IListItem>[]>([
    {
      key: 'class',
      label: 'class',
      width: 100,
      align: 'center',
    },
    {
      key: 'id',
      label: 'No',
      width: 100,
    },
    {
      key: 'title',
      label: 'Title',
      width: 300,
      itemRender: ({ values }) => {
        return (
          <>
            {values.writer} / {values.title}
          </>
        );
      },
    },
    {
      key: 'writer',
      label: 'Writer',
      width: 100,
      itemRender: ({ values: values }) => {
        return <>{values.writer} / A</>;
      },
    },
    {
      key: 'createAt',
      label: 'Date-A',
      width: 100,
      align: 'center',
    },
    {
      key: 'createAt',
      label: 'Date-B',
      width: 100,
      align: 'center',
    },
    {
      key: 'createAt',
      label: 'Date-C',
      width: 100,
      align: 'center',
    },
    {
      key: 'createAt',
      label: 'Date-D',
      width: 100,
    },
    {
      key: 'createAt',
      label: 'Date-E',
      width: 100,
    },
  ]);

  const containerRef = React.useRef<HTMLDivElement>(null);
  const { width: containerWidth, height: containerHeight } = useContainerSize(containerRef);

  useEffect(() => {
    setSummary(summaryKey === 'summary1' ? summary1 : summary2);
  }, [summaryKey]);

  return (
    <>
      <Radio.Group
        style={{ marginBottom: 10 }}
        options={[
          { label: 'TOP', value: 'summary1' },
          { label: 'Bottom', value: 'summary2' },
        ]}
        onChange={e => {
          setSummaryKey(e.target.value);
        }}
        value={summaryKey}
      />

      <DataGridContainer ref={containerRef}>
        <AXDataGrid<IListItem>
          showLineNumber
          rowChecked={{
            checkedIndexes: [],
            onChange: (ids, selectedAll) => {
              console.log('onChange rowSelection', ids, selectedAll);
            },
          }}
          frozenColumnIndex={1}
          width={containerWidth}
          height={containerHeight}
          data={list}
          columns={columns}
          onChangeColumns={(columnIndex, { width, columns }) => {
            console.log('onChangeColumnWidths', columnIndex, width, columns);
            setColumns(columns);
          }}
          cellMergeOptions={{
            columnsMap: {
              0: { mergeBy: 'class' },
              4: { mergeBy: 'class' },
              5: { mergeBy: 'class' },
              6: { mergeBy: 'class' },
            },
          }}
          onClick={item => console.log(item)}
          variant={'vertical-bordered'}
          summary={summary}
        />
      </DataGridContainer>
    </>
  );
}

export default SummaryExample;

Summary 설정

summary는 일반 <table>이나 <tr>을 직접 반환하는 렌더 prop이 아닙니다. 표시 위치와 요약할 컬럼 정의 배열을 전달합니다.

const summary: AXDGProps<Row>['summary'] = {
  position: 'bottom',
  columns: [
    {
      columnIndex: 0,
      colSpan: 2,
      align: 'center',
      itemRender: () => <>합계</>,
    },
    {
      columnIndex: 2,
      align: 'right',
      itemRender: ({ data }) => (
        <>{data.reduce((sum, item) => sum + item.values.amount, 0).toLocaleString()}</>
      ),
    },
  ],
};

<AXDataGrid summary={summary} summaryHeight={32} {...props} />

멤버 의미

멤버 설명
position 요약 행을 데이터 위(top) 또는 아래(bottom)에 배치합니다.
columnIndex 요약 셀이 시작될 컬럼의 0 기반 인덱스입니다.
colSpan 요약 셀이 차지할 컬럼 수입니다.
itemRender { column, columnIndex, data }를 받아 요약 콘텐츠를 반환합니다.
summaryHeight 요약 영역의 높이를 조정하는 최상위 prop입니다.

dataAXDGDataItem<T>[]이므로 실제 값은 item.values에서 읽습니다. 페이지 단위 합계인지 전체 데이터 합계인지는 부모가 그리드에 어떤 데이터를 전달했는지에 따라 결정됩니다.