기존에 react.js로 진행중이던 todoList의 기능을 추가하던중 drag and drop기능을 추가하여 보았다.
//npm 설치
yarn add react-beautiful-dnd
rbd는 drag and drop을 쉽게 구현할수 있게 해주는 npm이다.
//기존 컴포넌트 (todoList.jsx)
return (
<Styled.ListContainer>
{todoReducer.map((list, index) => (
<TodoItem/>
))}
</Styled.ListContainer>
);
//DragDropContext, Droppable로 감싸기
import {
DragDropContext,
Droppable,
} from "react-beautiful-dnd";
return (
<DragDropContext> //*
<Droppable> //*
<Styled.ListContainer>
{todoReducer.map((list, index) => (
<TodoItem/>
))}
</Styled.ListContainer>
</Droppable>
</DragDropContext>
);
1.import {DragDropContext, Droppable} from "react-beautiful-dnd" 한다.
2. 드래그할 리스트의 가장 부모 태그를 래핑한다. (provider와 비슷한 기능으로 생각하면된다.)
return (
<DragDropContext>
<Droppable droppableId='droppableLists'> // *
{(provided) => { //*
return (
<Styled.ListContainer
{...provided.droppableProps} //*
ref={provided.innerRef} //*
>
{todoReducer.map((list, index) => (
<TodoItem/>
))}
</Styled.ListContainer>
);
}}
</Droppable>
</DragDropContext>
);
return (
<DragDropContext onDragEnd={onDragEndHandeler}>
<Droppable droppableId='droppableLists'>
{(provided) => {
return (
<Styled.ListContainer
{...provided.droppableProps}
ref={provided.innerRef}
>
{todoReducer.map((list, index) => (
<Draggable //*
key={list.id} //*
draggableId={`${list.id}`} //*
index={index} //*
>
{(provided) => ( //*
<TodoItem
provided={provided} //*
/>
)}
</Draggable>
))}
</Styled.ListContainer>
);
}}
</Droppable>
</DragDropContext>
);
//todoItem.jsx
return (
<Styled.ListContainer
ref={provided.innerRef} //*
{...provided.draggableProps} //*
{...provided.dragHandleProps} //*
>
{todoList}
</Styled.ListContainer>
);
여기까지하면 기본설정이 끝난것이다. 그러나 드래그를 해보면 에러가 나고 리스트의 사단 모양이 잡히지 않는다.
return (
<DragDropContext onDragEnd={onDragEndHandeler}>
<Droppable droppableId='droppableLists'>
{(provided) => {
return (
<Styled.ListContainer
{...provided.droppableProps}
ref={provided.innerRef}
>
{todoReducer.map((list, index) => (
<Draggable
key={list.id}
draggableId={`${list.id}`}
index={index}
>
{(provided) => (
<TodoItem
provided={provided}
/>
)}
</Draggable>
))}
{provided.placeholder} //*
</Styled.ListContainer>
);
}}
</Droppable>
</DragDropContext>
);
이제 하단 모양이 드래그시 잘 잡혀있다.
const onDragEndHandeler = (result) => {
console.log(result.source)
console.log(result.destination)
};
<DragDropContext onDragEnd={onDragEndHandeler}>
const onDragEndHandeler = (result) => {
const currentList = todoReducer;
const startTagIndex = result.source.index;
const destinationTagIndex = result.destination.index;
const [startTag] = Array.from(currentList).splice(startTagIndex, 1);
dispatch(listMove({ startTagIndex, startTag, destinationTagIndex }));
};
2.todoList는 reduxToolkit을 사용하고 있었기에 todoReducer에서 list를 받아왔다.
2-1. currentList에서 splice로 드래그할 태그를 뺀다
2-2. dispatch를 이용하여 (startTagIndex, startTag, destinationTagIndex) 를 payload로 보내준다.
//todoReducer
export const todoReducer = createSlice({
name: "todos",
initialState: [],
reducers: {
listMove: (state, { payload }) => {
state.splice(payload.startTagIndex, 1);
state.splice(payload.destinationTagIndex, 0, payload.startTag);
},
},
});
state에서 드래그할 태그의index를 삭제 후 drop할 태그의 인덱스전으로 다시 집어넣는 기능을 구현하였다.