분명 시작할땐 트렐로 클론코딩이었는데... 이것저것 하다보니 내 맘대로 만들어버린 칸반보드를 통해 배운 것들을 정리하고자 한다.
사실 것들 이라기엔... 이리저리 머리 굴린거 + beautiful dnd 사용법 익힌게 전부인 것 같다 ㅋㅋ
https://trello-clone-lake-six.vercel.app/
https://github.com/sjoleee/trello-clone
간단하게 적자면,
하나씩 들여다보자.
DragDropContext는 3개의 prop을 갖는다.
이 중에서 onDragEnd만이 필수.
const onDragEnd = () => {};
return (
<DragDropContext onDragEnd={onDragEnd}>
<div></div>
</DragDropContext>
);
또한, DragDropContext은 반드시 자식을 가져야한다.(당연한 거긴 하지..)
대충 빈 함수를 만들어서 넣어줬다.
이 안에 Droppable이 있어야하고, 그 안에 Draggable이 있어야 한다.
말 그대로, 뭔가를 드롭할 수 있는 공간을 설정해준다.
Droppable는 droppableId라는 prop을 필수로 가져야한다.
droppableId는 고유한 값이어야함!
그리고 type이라는 prop을 가질 수 있다. 따로 설정해주지 않으면 DEFAULT로 설정되는데, 이 type이 동일한 Droppable과 Draggable이 상호작용 가능하게 된다. drag and drop를 중첩하여 사용하고 싶을 경우, 이 prop을 사용하면 된다.
isDragDisabled은 drag 가능한지 상태를 말한다. 기본으로 false로 가능하게 설정되어있다.
const onDragEnd = () => {};
return (
<DragDropContext onDragEnd={onDragEnd}>
<div>
<Droppable droppableId="testDrop">
{() => <div></div>}
</Droppable>
</div>
</DragDropContext>
);
또한, DragDropContext와 마찬가지로 반드시 자식을 가지는데..
이게 뭔가 싶겠지만 함수 형태로 넣어줘야 한다.
왜일까.. latch라는 키워드가 나오던데 궁금하다. 알아봐야겠다.
일단 사용법에 대해 계속 기록하자면,
이 함수는 provided와 snapshot이라는 2개의 인자를 가진다.
두 인자의 type definition을 보자.
export interface DroppableProvided {
innerRef: (element: HTMLElement | null) => any;
placeholder?: React.ReactElement<HTMLElement> | null | undefined;
droppableProps: DroppableProvidedProps;
}
export interface DroppableStateSnapshot {
isDraggingOver: boolean;
draggingOverWith?: DraggableId | undefined;
draggingFromThisWith?: DraggableId | undefined;
isUsingPlaceholder: boolean;
}
차근차근 살펴보자.
droppable이 올바르게 작동하려면, 당신은 반드시 provided.innerRef를 ReactElement의 최상단 DOM 노드에 바인드(bind)해야 합니다. 우리는 ReactDOM를 사용하지 않기 위해 당신의 DOM 노드를 찾을 것입니다.
무슨말이지...? 해석이 필요할 듯 하다 ㅜㅠㅠ
일단, 사용법은 최상단 노드에 바인드하라는 것인데, 이유에 대해 정확히 알고싶다.
placeholder는 drag and drop중에, droppable의 면적이 변화해야 할 일이 생기게 되면, 해당 부분을 처리해주는 React Element라고 한다.
그러니까, drag 중에 droppable 영역이 축소되지 않도록 해주는 역할이라고 함.
provided.placeholder (?ReactElement) The Draggable element has position: fixed applied to it while it is dragging. The role of the placeholder is to sit in the place that the Draggable was during a drag. It is needed to stop the Droppable list from collapsing when you drag. It is advised to render it as a sibling to the Draggable node. When the library moves to React 16 the placeholder will be removed from api.
droppableProps는 droppable로 사용할 컴포넌트에 필요한 props를 모아 놓은 것. 깔끔하게 스프레드 연산자로 처리하는게 일반적이다.
isDraggingOver
drag요소가 내 위에 있나요~?로 boolean이다.
draggingOverWith
내 위로 지나가는 drag요소의 ID가 뭐에요?로 draggableId이다.
draggingFromThisWith
여기서 출발하는 drag요소의 ID가 뭐에요?로 draggableId이다.
출발해서 droppable를 떠나면 null인듯(확인 안해봄)
스타일할때 사용하면 좋다.
isUsingPlaceholder
provided.placeholder가 사용중인지를 알려준다.
Draggable은 Drag할 수 있는 요소를 감싼다.
Droppable과 마찬가지로 필수로 props를 가지는데, droppableId와 index를 가진다.
index를 가져야 하는 이유는... 드래그해서 자리를 옮기려면 순서라는게 있어야 하기 때문이다.
둘 다 고유한 값이어야 한다.
Droppable과 마찬가지로 함수를 통해 드래그할 컴포넌트를 반환해줘야 함.
함수는 provided와 snapshot를 인자로 갖는다.
두 인자의 type definition을 보자.
export interface DraggableProvided {
// will be removed after move to react 16
innerRef: (element?: HTMLElement | null) => any;
draggableProps: DraggableProvidedDraggableProps;
dragHandleProps?: DraggableProvidedDragHandleProps | undefined;
}
export interface DraggableStateSnapshot {
isDragging: boolean;
isDropAnimating: boolean;
dropAnimation?: DropAnimation | undefined;
draggingOver?: DroppableId | undefined;
// the id of a draggable that you are combining with
combineWith?: DraggableId | undefined;
// a combine target is being dragged over by
combineTargetFor?: DraggableId | undefined;
// What type of movement is being done: 'FLUID' or 'SNAP'
mode?: MovementMode | undefined;
}
isDragging
제가 drag 되고 있나요?
isDropAnimating
dropAnimation이 진행중인가요?
dropAnimation
dropAnimation에 대한 정보
draggingOver
지금 어떤 droppable위를 지나가고 있나요?
combine과 관련된 프로퍼티들은 잘 모르겠다 ㅠㅠ
간단한 결과물
onDragEnd가 void라서 옮겨지지는 않음
const onDragEnd = () => {};
return (
<DragDropContext onDragEnd={onDragEnd}>
<div>
<Droppable droppableId="testDrop">
{(provided, snapshot) => (
<div ref={provided.innerRef} {...provided.droppableProps}>
<Draggable draggableId="testDrag0" index={0}>
{(provided) => (
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
>
1번
</div>
)}
</Draggable>
<Draggable draggableId="testDrag1" index={1}>
{(provided) => (
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
>
2번
</div>
)}
</Draggable>
{provided.placeholder}
</div>
)}
</Droppable>
</div>
</DragDropContext>
);