React — 두 항목 위치 교환
React에서 두 항목만 교환하는 swap과 완료 이벤트를 확인합니다.
삽입 정렬과 다른 결과
섹션 제목: “삽입 정렬과 다른 결과”[A, B, C, D]에서 A를 C 중앙에 놓으면 [C, B, A, D]가 됩니다. 두 항목만 위치를 교환하고 B와 D는 유지합니다. 일반 삽입 정렬처럼 중간 항목을 밀어내는 동작이 아닙니다.
- A 손잡이를 C 중앙까지 드래그하여 놓습니다.
- 결과 JSON에서
status: "dropped",change.operation: "swap",change.itemId: "A",change.swapItemId: "C"를 확인합니다. - 드래그를 시작한 뒤 Escape로 취소하면 순서가 유지됩니다.
- 초기화하면 A, B, C, D 순서로 돌아옵니다.
공개 옵션
섹션 제목: “공개 옵션”| 옵션 | 값/역할 |
|---|---|
swap |
true — 같은 영역에서 출발 항목과 대상 항목만 교환합니다. |
direction |
"vertical" — 이 예제의 단일 세로 목록 기준입니다. |
itemKey 또는 data-sortable-id |
이동 전후 유지되는 안정 ID를 지정합니다. |
handle |
".task-handle" — 포인터 입력을 손잡이로 제한합니다. |
React 상태 반영
섹션 제목: “React 상태 반영”SortableRoot → SortableArea · items / onItemsChange
어댑터가 전달하는 다음 배열을 즉시 상태에 반영합니다. 원본 배열을 직접 바꾸거나 index를 key로 사용하지 않습니다. onAfterDrag의 완료 결과와 표시 순서를 함께 확인합니다.
적용 범위
섹션 제목: “적용 범위”이 예제는 같은 영역의 단일 항목 Swap입니다. Grid collision, multiDrag, threshold/invertSwap와의 조합, 여러 영역 사이의 전달은 별도 시나리오입니다. 포인터 기반 예제이며 드래그 handle의 focus가 전체 키보드 정렬 지원을 뜻하지 않습니다.
관련 문서
섹션 제목: “관련 문서”고급 정렬 가이드 · Core 생명주기 · Vanilla 인스턴스 · 일반 목록 이동
직접 실행
섹션 제목: “직접 실행”import { useState } from 'react';import { SortableRoot, SortableArea } from 'comins-sortable/react';import type { AfterDragResult } from 'comins-sortable/core';import 'comins-sortable/styles.css';type Item = { id: string };const initial: Item[] = ['A', 'B', 'C', 'D'].map(id => ({ id }));export default function ReactSwap({ lang = 'ko' }: { lang?: string }) { const ko = lang === 'ko'; const [items, setItems] = useState(initial); const [result, setResult] = useState<AfterDragResult | null>(null); return <div className="demo" data-demo="swap-react"> <div className="demo-toolbar"><span>{ko ? 'A의 손잡이를 C의 중앙에 놓으십시오.' : 'Drop the A handle onto the center of C.'}</span><button onClick={() => { setItems(initial); setResult(null); }}>{ko ? '초기화' : 'Reset'}</button></div> <SortableRoot<Item> onAfterDrag={setResult}> <SortableArea<Item> areaId="items" items={items} itemKey="id" swap direction="vertical" handle=".task-handle" onItemsChange={next => setItems([...next])} areaProps={{ className: 'task-list swap-list' }}> {item => <div className="task" data-swap-id={item.id}><button className="task-handle" aria-label={`Drag ${item.id}`}>⠿</button><span>{item.id}</span></div>} </SortableArea> </SortableRoot> <p role="status" data-swap-order>{items.map(item => item.id).join(', ')}</p> <pre data-swap-result>{JSON.stringify(result, null, 2)}</pre> </div>;}