시작하기 (Getting Started)
AXBOOT DataGrid의 설치부터 CSS 임포트, 기본 데이터 바인딩 및 첫 번째 그리드 렌더링까지 단계별로 알아봅니다.
import * as React from 'react';
import { AXDataGrid, AXDGColumn } from '@axboot/datagrid';
import { useContainerSize } from '../hooks/useContainerSize';
import DataGridContainer from '../components/DataGridContainer';
interface Props {}
interface IListItem {
id: string;
title: string;
writer: string;
createAt: string;
}
const list = Array.from(Array(5)).map((v, i) => ({
values: {
id: `ID_${i}`,
title: `title_${i}`,
writer: `writer_${i}`,
createAt: `2022-09-08`,
},
}));
function BasicExample(props: Props) {
const [columns, setColumns] = React.useState<AXDGColumn<IListItem>[]>([
{
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,
},
{
key: 'createAt',
label: 'Date-B',
width: 100,
},
{
key: 'createAt',
label: 'Date-C',
width: 100,
},
{
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);
return (
<DataGridContainer ref={containerRef}>
<AXDataGrid<IListItem>
width={containerWidth}
height={containerHeight}
data={list}
columns={columns}
onChangeColumns={(columnIndex, { width, columns }) => {
console.log('onChangeColumnWidths', columnIndex, width, columns);
setColumns(columns);
}}
// rowChecked={{
// checkedIndexes: [],
// onChange: (ids, selectedAll) => {
// console.log('onChange rowSelection', ids, selectedAll);
// },
// }}
onClick={item => console.log(item)}
/>
</DataGridContainer>
);
}
export default BasicExample;import * as React from 'react';
import './DataGridContainer.css';
interface DataGridContainerProps extends React.HTMLAttributes<HTMLDivElement> {
children?: React.ReactNode;
}
/**
* Keeps a DataGrid in a measured, fixed layout box.
*
* AXDataGrid's rendered root is absolutely positioned within this relative
* container. This makes a ResizeObserver measurement authoritative when a
* surrounding flex or grid layout shrinks as well as when it expands.
*/
const DataGridContainer = React.forwardRef<HTMLDivElement, DataGridContainerProps>(
({ className, ...rest }, ref) => (
<div ref={ref} className={`data-grid-container ${className ?? ''}`.trim()} {...rest} />
),
);
DataGridContainer.displayName = 'DataGridContainer';
export default DataGridContainer;.data-grid-container {
position: relative;
width: 100%;
height: 400px;
overflow: hidden;
font-size: 13px;
}
.data-grid-container > .axdg-root {
position: absolute;
inset: 0;
}import * as React from 'react';
export function useContainerSize(ref: React.MutableRefObject<HTMLElement | null>, additionalDeps: unknown[] = []) {
const [width, setWidth] = React.useState(0);
const [height, setHeight] = React.useState(0);
const resizeObserver = React.useRef(
new ResizeObserver(entries => {
if (entries.length !== 1) {
throw new Error('Invalid Container length');
}
const [entry] = entries;
const { width, height } = entry.contentRect;
setWidth(width);
setHeight(height);
}),
);
React.useEffect(() => {
if (!ref.current) return;
const observer = resizeObserver.current;
const element = ref.current;
setWidth(element.clientWidth);
setHeight(element.clientHeight);
observer.observe(element);
return () => {
observer.unobserve(element);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [...additionalDeps, ref]);
return {
width,
height,
};
}1. 개요 및 왜 AXBOOT DataGrid인가?
안녕하세요! React 비즈니스 웹 애플리케이션을 개발하다 보면 관리자 대시보드, ERP, CRM, 정산 시스템 등에서 수천~수만 건의 데이터를 빠르고 안정적으로 렌더링하는 데이터 테이블이 반드시 필요합니다.
AXBOOT DataGrid는 React 업무 화면에서 가상 스크롤, 고정 열, 셀 편집, 셀 병합 같은 기능을 하나의 TypeScript 컴포넌트 API로 구성할 수 있게 합니다. 라이선스 상태는 확정 전이므로 배포 전에 도입 환경 안내와 저장소의 LICENSE를 확인하세요.
@axboot/datagrid는 다음과 같은 핵심 철학으로 만들어졌습니다:
- React 컴포넌트 구조: 애플리케이션 상태와 이벤트 흐름에 DataGrid를 직접 연결
- 행 가상 스크롤(Virtual Scrolling): 현재 viewport에 필요한 행을 중심으로 렌더링
- TypeScript 제네릭 지원: 셀 렌더러와 이벤트 콜백에서 행 데이터 타입 전달
- 표준 DOM 기반 렌더링: 셀과 헤더를 DOM 및 CSS 클래스·변수로 표현
2. 패키지 설치
터미널에서 선호하는 패키지 매니저로 설치합니다:
# npm 사용 시
npm install @axboot/datagrid
# yarn 사용 시
yarn add @axboot/datagrid
# pnpm 사용 시
pnpm add @axboot/datagrid
Peer Dependencies 안내: 현재 패키지의 정확한 React 및 ReactDOM 피어 의존성 범위는 설치 전에
package.json또는 npm 패키지 정보를 확인하세요.
3. 필수 스타일시트(CSS) 임포트
DataGrid의 레이아웃, 셀 테두리, 가상 스크롤바, 헤더 툴박스가 정상적으로 렌더링되려면 라이브러리 CSS를 프로젝트 진입점(예: App.tsx, main.tsx, index.tsx, 혹은 글로벌 레이아웃)에서 반드시 한 번 임포트해야 합니다.
// 전역 엔트리 파일 (main.tsx 또는 App.tsx)
import '@axboot/datagrid/style.css';
💡 스타일 격리 안내:
@axboot/datagrid/style.css는.axdg-*클래스와--axdg-*변수를 사용해 그리드 스타일을 제공합니다. 매우 구체적인 전역 선택자나!important규칙은 여전히 영향을 줄 수 있으므로, 애플리케이션의 전역 CSS는 가능한 한 페이지 wrapper 아래로 범위를 제한하세요.
4. 첫 번째 DataGrid 만들기 (단계별 따라하기)
가장 간단한 사용자 목록 표를 만들어보겠습니다.
1단계: 행 데이터 타입 정의
먼저 표시할 비즈니스 데이터의 인터페이스를 작성합니다.
interface UserItem {
id: number;
name: string;
department: string;
role: string;
email: string;
}
2단계: 컬럼(Columns) 정의
컬럼 목록은 AXDGColumn<T>[] 타입으로 정의합니다. key는 데이터 객체의 속성 이름과 일치해야 합니다.
import type { AXDGColumn } from '@axboot/datagrid';
const columns: AXDGColumn<UserItem>[] = [
{ key: 'id', label: '사번', width: 80, align: 'center' },
{ key: 'name', label: '이름', width: 120 },
{ key: 'department', label: '부서', width: 150 },
{ key: 'role', label: '직책', width: 120 },
{ key: 'email', label: '이메일', width: 220 },
];
3단계: 행 데이터(Data) 래핑 구조
AXBOOT DataGrid의 행 데이터는 { values: T } 형태로 래핑된 AXDGDataItem<T>[] 배열을 전달해야 합니다. (선택 상태, 상태 뱃지, 유효성 검사 메타데이터를 효율적으로 관리하기 위함입니다.)
import type { AXDGDataItem } from '@axboot/datagrid';
const data: AXDGDataItem<UserItem>[] = [
{ values: { id: 101, name: '김민수', department: '플랫폼개발팀', role: '수석연구원', email: 'ms.kim@example.com' } },
{ values: { id: 102, name: '이수진', department: '디자인시스템팀', role: '책임디자이너', email: 'sj.lee@example.com' } },
{ values: { id: 103, name: '박도현', department: '데이터엔지니어링', role: '선임연구원', email: 'dh.park@example.com' } },
];
4단계: 컴포넌트 렌더링
import React from 'react';
import { AXDataGrid } from '@axboot/datagrid';
export default function UserListGrid() {
return (
<div style={{ width: '100%', height: 400 }}>
<AXDataGrid<UserItem>
width={800}
height={400}
columns={columns}
data={data}
rowKey="id"
headerHeight={34}
itemHeight={28}
/>
</div>
);
}
5. 핵심 개념 및 필수 규칙
1) 너비(width)와 높이(height)는 필수입니다
AXBOOT DataGrid는 고성능 가상 스크롤 엔진을 내장하고 있어, 뷰포트에 표시될 행의 개수(displayItemCount = height / itemHeight)를 픽셀 단위로 정확히 계산합니다.
따라서 width와 height prop에 유효한 숫자(픽셀)를 전달해야 합니다.
💡 부모 컨테이너에 맞춘 반응형 너비/높이 팁: 브라우저 리사이즈나 유동적인 Flex/Grid 레이아웃에 맞추려면
ResizeObserver훅(예:useContainerSize또는react-use-measure)을 사용하여 부모div의 크기를 측정해AXDataGrid의width,height에 넘겨주는 패턴을 사용합니다.
2) 고유 식별자 rowKey를 지정하세요
행 선택(Selection), 포커스, 셀 편집 상태를 안정적으로 유지하기 위해 행 데이터에서 고유한 값을 가지는 필드명(예: 'id', 'uuid', 'code')을 rowKey="id"로 지정하는 것을 강력히 권장합니다.
3) 중첩 객체 접근 (key에 배열 사용 가능)
만약 데이터가 { user: { profile: { name: '홍길동' } } } 처럼 중첩되어 있다면, 컬럼 key에 점 경로 배열을 전달할 수 있습니다:
{ key: ['user', 'profile', 'name'], label: '사용자명', width: 120 }
6. 실무 주의사항 (Gotchas)
[!CAUTION] 흔한 실수 1:
data배열에 원시 객체를 바로 전달하는 경우data={[{ id: 1, name: 'A' }]}형태로 넘기면 안 되며, 반드시data={[{ values: { id: 1, name: 'A' } }]}처럼values프로퍼티로 감싸서 전달해야 합니다.
[!TIP] 성능 팁 2:
columns배열은 컴포넌트 외부에 선언하거나useMemo로 감싸세요 렌더링마다 새columns객체가 생성되면 내부 컬럼 오프셋 재계산이 발생할 수 있습니다. 상수로 선언하거나useMemo를 활용하세요.
7. 다음 단계 가이드
이제 기초를 마쳤습니다! 다음 가이드에서 더 강력한 업무용 기능들을 살펴보세요: