[POB#32] Assignment 8 : 모두컴퍼니 기업 과제. Drag and Drop 기능 구현 ( React )
Assignment 8 과제를 통해 얻은 지식 정리 글입니다.
과제 레파지토리 : https://github.com/6trillion/Assignmet8-TeamA
Drag and Drop 구현 ( React )
이전 글 VanillaJS로 구현한 Drag and Drop을 React로 구현해봤습니다.
사용한 이벤트는 같습니다. React에선 DOM을 직접 접근하는 것을 추천하지 않기 때문에 최소한으로 접근하면서 구현했습니다.
useRef
JS에선 querySelector
, queryElementById
등으로 DOM에 접근하지만 React에선 특수한 경우에만 DOM에 직접 접근하기 때문에 useRef hook
을 이용해 필요할 때만 접근합니다.
const ContainerRef = useRef();
return <Container ref={AreaRef}>...</Container>;
querySelectorAll
과 같이 다수의 DOM을 저장하기 위해서 useRef의 초깃값을 배열로 선언합니다.
React에서 동일한 레이아웃은 거의 다 재사용을 하기 때문에 ref를 하위 컴포넌트로 전달해야 합니다. ref를 하위 컴포넌트로 전달할 땐 forwardRef
로 하위 컴포넌트를 감싸줘야 부모 컴포넌트에서 ref를 사용할 수 있습니다.
const DraggableRef = useRef([]);
return (
{TodoItems.map((item) => (
<Todo key={item.id} todo={item}
ref={(r) => DraggableRef() = r}
/>
))}
)
const Todo = ({ todo }, ref) => {
return <Draggable ref={ref}>{todo.id}</Draggable>;
};
export default forwardRef(Todo);
onDragStart, onDragEed 이벤트
JS에선 드래그한 속성에 dragging이라는 class를 추가해 식별했지만, DOM을 직접 접근하지 않기 때문에 드래그한 속성의 todos만을 저장했습니다.
const handleDragStart = useCallback(
(todo) => {
setDragTodo(todo);
},
[setDragTodo]
);
const handleDragEnd = useCallback(() => {
setDragTodo(null);
}, [setDragTodo]);
return (
<Draggable
draggable
ref={ref}
onDragStart={() => handleDragStart(todo)}
onDragEnd={handleDragEnd}
>
{todo.id}
</Draggable>
);
onDragOver 이벤트
DragOver
이벤트도 마찬가지입니다. appendChild
나 insertBefore
를 사용하지 않기 때문에 element
가 아닌 다른 속성의 값을 가져와 조작해야 합니다.
따라서 JS와는 다르게 지나고 있는 속성의 element
가 아닌 속성의 index
인 afterIndex
를 반환합니다.
afterIndex
가 null 일 때, 가장 아래에 있어 index를 가져올 수 없을 때, 현재 드래그한 todo를 지우고 가장 뒤에 추가해 줍니다.
afterIndex
가 특정 index를 가질 때, splice
를 이용해 현재 todo를 지우고, 특정 index 뒤에 추가시킵니다.
마지막으로 TodoItems
를 setState
하여 갱신 시켜줍니다.
return <Container onDragOver={handleDragOver}>...</Container>;
const handleDragOver = useCallback(
(e) => {
e.preventDefault();
const afterIndex = getDragAfterElement(e.clientY);
if (dragTodo) {
if (afterIndex === null) {
const nextState = [...todos];
const index = nextState.indexOf(dragTodo);
nextState.splice(index, 1);
nextState.push(dragTodo);
// setState(nextState)로 state 갱신
} else {
const nextState = [...todos];
const index = nextState.indexOf(dragTodo);
nextState.splice(index, 1);
nextState.splice(afterIndex, 0, dragTodo);
// setState(nextState)로 state 갱신
}
}
},
[getDragAfterElement, dragTodo, dispatch, todos]
);
getDragAfterElement 함수
JS와 로직은 비슷하지만 element
가 아닌 index
를 반환하는 것에서 차이가 있습니다. 배열로 만든 useRef를 이용해 todo의 모든 DOM에 대해 y 값으로 현재 지나고 있는 속성들이 index
를 반환합니다.
const getDragAfterElement = useCallback(y) => {
const draggableElements = [...ListRef.current.filter((v) => v !== undefined)];
return draggableElements.reduce(
(closest, child, index) => {
const box = child.getBoundingClientRect();
const offset = y - box.top - box.height / 2;
if (offset < 0 && offset > closest.offset) {
return { offset: offset, element: child, index: index };
} else {
return closest;
}
},
{ offset: Number.NEGATIVE_INFINITY }
).index;
}, []);
Author And Source
이 문제에 관하여([POB#32] Assignment 8 : 모두컴퍼니 기업 과제. Drag and Drop 기능 구현 ( React )), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@tunakim/POB32-Assignment-8-모두컴퍼니-기업-과제.-Drag-and-Drop-기능-구현-React저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)