so woon!

[REACT] Drag and Drop - 같은 보드 내에서 재정렬 본문

ReactJS/개념정리

[REACT] Drag and Drop - 같은 보드 내에서 재정렬

xowoony 2023. 4. 30. 18:07

학습일  : 2023. 04. 30


보드를 3개로 늘리면서

보드내에서 재정렬 하던 부분을 주석처리 해놓았었는데

다시 한번 구현해보고자 한다.


 

한개의 보드 내에서 드로그 앤 드롭 다시 구현하기

드롭할 때마다 onDragEnd 함수가 실행된다.

먼저, source의 droppableId가 destination의 droppableId와 같은지 체크해야 한다.
왜냐하면 아직 보드를 넘어다니지는 않고 한 보드 안에서 움직일 것이기 때문이다.


<App.tsx>
 

const onDragEnd = (info: DropResult) => {
    console.log(info);
    const {destination, draggableId, source} = info;
if(destination?.droppableId === source.droppableId) {
 // 같은 보드에서의 움직임
}




지금부터 할 것은 전에 했던 거랑 비슷한데
전에 array를 복사해서
그 array를 변형시킨(mutate) 다음 그걸 다시 새로운 array로 저장했다.


이제는 복사할 array가 없는 대신
atom.tsx에 여러 array가 들어있는(미리 작성해둔) object가 있다.
default에 작성해줬던 것이고,
Property들을 가진 object이며 각 property들이 array이다.


-로직-
만약 하나의 보드 내에서 그래그 앤 드롭을 다시 구현하고자 한다면
1.  수정이 일어난 보드만 복사한다.
2. 그리고 그 복사본을 기존 친구들 옆에 붙여준다.


복붙 전

<App.tsx>

   const onDragEnd = (info: DropResult) => {
    console.log(info);
    const {destination, draggableId, source} = info;
if(destination?.droppableId === source.droppableId) {
 // 전에 적어줬던 로직을 다시 붙여넣기 해줌
}




복붙 후

function App() {
  const [toDos, setToDos] = useRecoilState(toDoState);
  const onDragEnd = (info: DropResult) => {
    console.log(info);
    const { destination, draggableId, source } = info;
    if (destination?.droppableId === source.droppableId) {
      setToDos((oldToDos) => {
        const toDosCopy = [...oldToDos];
        toDosCopy.splice(source.index, 1);
        toDosCopy.splice(destination?.index, 0, draggableId);
        return toDosCopy;
      });
    }
  };





그런데 oldToDos는 더이상 array가 아니라서
...oldToDos 이렇게 쓸 수는 없으니 지워주고
이제 변화가 일어난 board만 복사해줄 것이다.

destination?.droppableId === source.droppableId 서로 같다는 전제 하라서
둘 중 아무거나 써줘도 상관 없음.
boardCopy를 만들어준다.
oldToDos로 들어가서 source.droppableId를 가져온다.





<App.tsx>
관련 로직은 주석으로 적었음.

function App() {
  const [toDos, setToDos] = useRecoilState(toDoState);
  // onDragEnd : 드래그가 끝났을 때 실행되는 함수
  // destination : 드래그 끝나는 시점의 도착지 정보
  // source : 드래그 시작 정보 - 움직임을 시작한 아이템의 index, droppableId를 알려줌
  const onDragEnd = (info: DropResult) => {
    console.log(info);
    const { destination, draggableId, source } = info;
   // destination이 정의되지 않았을 경우 그대로 리턴
    if(!destination) return;
    if (destination?.droppableId === source.droppableId) {
      setToDos((allBoards) => {
        // source의 droppableId로부터 array를 복사하는 과정
        const boardCopy = [...allBoards[source.droppableId]]; // toDo or Doing or Done의 array를 복사한다.
        // 1. source.index에서 아이템을 삭제한다.
        boardCopy.splice(source.index, 1); // source.index 즉 시작시점부터 1개만 지움
        // 2. item을 다시 destination.index에 넣고, 아무것도 추가하지 않고 item을 넣는다.
        // (item은 draggabledId 이다.)
        // (때때로 destination이 없을 수도 있다. 유저가 그자리에 그대로 둘 경우엔)
        boardCopy.splice(destination?.index, 0, draggableId);
        // boardCopy와, 이전의 State와, 다른 Boards를 모두 리턴해주어야 함
        // oldToDos는 object 였다.
        // oldToDos에서 모든걸 리턴할건데, 보드 딱 하나만 다른걸로 대체
        return {
          ...allBoards, // 다른 모든 board들을 가져오고
          [source.droppableId]: boardCopy, // 새로운 변형된 board. (복사본임)
        };
      });
    }
  };

  return (
    <DragDropContext onDragEnd={onDragEnd}>
      <Wrapper>
        {/* Object.keys(toDos) 까지 하면 board의 모든 Id를 받아왔음. */}
        {/* 그럼 그 boardId로 map을 이용해 새로운 board들을 만들어준다. */}
        <Boards>
          {Object.keys(toDos).map((boardId) => (
            <Board key={boardId} toDos={toDos[boardId]} boardId={boardId} />
          ))}
        </Boards>
      </Wrapper>
    </DragDropContext>
  );
}

export default App;





실행결과
하나의 보드 내에서만 드로그 앤 드롭이 가능함을 볼 수 있음.

 

Comments