행 순서 재배치 (Row Reorder)

행 좌측의 드래그 핸들을 잡고 위아래로 드래그하여 데이터 행의 표시 순서를 직관적으로 변경하는 방법을 학습합니다.

#reorder#drag-handle#onReorder#pointer-drag#drag-and-drop
검토일: 2026-08-22
GitHub
import * as React from 'react';
import { AXDataGrid, AXDGColumn, AXDGDataItemStatus } from '@axboot/datagrid';
import { useContainerSize } from '../hooks/useContainerSize';
import DataGridContainer from '../components/DataGridContainer';
import { useState } from 'react';

interface Props {}

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

const _list = Array.from(Array(100)).map((v, i) => ({
  values: {
    id: `ID_${i}`,
    title: `title_${i}`,
    writer: `writer_${i}`,
    createAt: `2022-09-08`,
  },
}));

export default function ReorderExample(props: Props) {
  const [columns, setColumns] = useState<AXDGColumn<IListItem>[]>([
    {
      key: '_',
      label: '상태',
      width: 50,
      align: 'center',
      itemRender: ({ item }) => {
        return <>{item.status !== undefined ? AXDGDataItemStatus[item.status] : ''}</>;
      },
      getClassName: item => {
        return item.status ? 'editable' : '';
      },
    },
    {
      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 [list, setList] = useState(_list);

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

  return (
    <DataGridContainer ref={containerRef} className={'editor-example'}>
      <AXDataGrid<IListItem>
        width={containerWidth}
        height={containerHeight}
        data={list}
        columns={columns}
        onClick={item => console.log(item)}
        columnSortable={false}
        showLineNumber
        reorder={{
          enabled: true, // Set to true to enable drag-and-drop reordering
          onReorder: data => {
            // console.log('Reordered data:', data);
            setList(data);
            return true;
          },
        }}
      />
    </DataGridContainer>
  );
}

1. 언제 사용하며 왜 필요한가요?

메뉴 관리(Menu Tree), 배너 노출 우선순위 설정, 할 일(TODO) 순서 변경 등 **“사용자가 직접 항목의 순서를 조정하여 저장해야 하는 기능”**에서 행 드래그 재배치는 필수적인 UX입니다.

AXBOOT DataGrid의 reorder 기능을 활성화하면:

  • 행 번호 영역 좌측에 전용 드래그 핸들 아이콘(grip-vertical)이 자동 표시됩니다.
  • 행을 잡고 위아래로 끌어다 놓으면 onReorder 콜백이 트리거되어 새 배열을 즉시 전달합니다.
  • 가상 스크롤 상태에서도 포인터 위치와 실제 스크롤 오프셋을 기준으로 대상 행을 계산합니다.

2. 실무 완성형 예제: 배너 노출 순서 관리 그리드

import React, { useState } from 'react';
import { AXDataGrid, type AXDGColumn, type AXDGDataItem } from '@axboot/datagrid';

interface BannerItem {
  id: number;
  title: string;
  linkUrl: string;
  active: boolean;
}

export default function BannerReorderGrid() {
  const [data, setData] = useState<AXDGDataItem<BannerItem>[]>([
    { values: { id: 1, title: '메인 상단 여름 시즌 프로모션 배너', linkUrl: '/events/summer', active: true } },
    { values: { id: 2, title: '신규 회원 가입 10% 웰컴 쿠폰 안내', linkUrl: '/welcome', active: true } },
    { values: { id: 3, title: '카카오페이 결제 시 5천원 즉시 할인', linkUrl: '/events/kakaopay', active: false } },
    { values: { id: 4, title: '프리미엄 멤버십 오픈 기념 이벤트', linkUrl: '/membership', active: true } },
  ]);

  const columns: AXDGColumn<BannerItem>[] = [
    { key: 'id', label: 'ID', width: 60, align: 'center' },
    { key: 'title', label: '배너 제목', width: 280 },
    { key: 'linkUrl', label: '연결 링크', width: 180 },
    {
      key: 'active',
      label: '노출여부',
      width: 90,
      align: 'center',
      itemRender: ({ values }) => (
        <span style={{ color: values.active ? '#16a34a' : '#94a3b8', fontWeight: 600 }}>
          {values.active ? '노출중' : '비활성'}
        </span>
      ),
    },
  ];

  return (
    <div>
      <div style={{ marginBottom: 10, fontSize: 13, color: '#475569' }}>
        💡 행 좌측의 드래그 핸들(점 6개 아이콘)을 마우스로 잡고 위아래로 끌어서 순서를 변경해보세요.
      </div>

      <AXDataGrid<BannerItem>
        width={720}
        height={260}
        columns={columns}
        data={data}
        rowKey="id"
        showLineNumber={true} // 줄번호 영역 표시 (필수)
        reorder={{
          enabled: true, // 행 드래그 재배치 활성화
          onReorder: (newData: AXDGDataItem<BannerItem>[]) => {
            console.log('재배치 완료:', newData.map(d => d.values.title));
            setData(newData);
            return true; // 성공 시 true 반환
          },
        }}
      />
    </div>
  );
}

3. 실무 팁 & 주의사항 (Gotchas)

[!IMPORTANT] 정렬/필터 활성화 시 행 재배치 비활성화: 컬럼 정렬이나 필터가 걸려 있는 상태에서는 데이터의 인덱스가 왜곡되므로, 행 순서를 직접 드래그하여 변경하려면 정렬과 필터가 없는 원본 목록 상태에서 수행하는 것이 안전합니다.