so woon!

[React] Drag and Drop - multi board 만들기 본문

ReactJS/개념정리

[React] Drag and Drop - multi board 만들기

xowoony 2023. 4. 29. 20:10

학습일 : 2023. 04. 29


저번 글에 이어서

이번에는 멀티 보드를 만들어 보고자 한다.

기존에는 보드가 1개였다면

이번에는 3개로 늘려볼 것이다.


 

<atom.tsx>
일단 state 즉 default를 object로 변경해서 만들어주겠다.
이 object는 각각의 보드가 가질 id를 포함하게 될 것이다.
to_do, doing, done 이렇게 세개의 보드를 만들어 주었다.



import { atom } from "recoil";

export const toDoState = atom({
  key: "toDo",
  // default를 기존의 배열에서 -> object로 변경해준다.
  default: {
    // to_do, doing, done 은 배열을 가진다.
    to_do: ["a", "b"],
    doing: ["c", "d", "e"],
    done: ["f"],
  },
});




다른 보드로 Drop을 하기 위해서 뭔가 추가할 내용은 없고
한 array에서 지우고, 다른 array에다 붙여넣으면 되는데
이전에 했던 로직과 똑같이 하면 된다.


<App.tsx>
map에서 에러가 나고 있는데,
map은 object가 아닌 array에서만 사용할 수 있기 때문이다.
따라서

App.tsx에서

 <Droppable droppableId="one">
    {(magic) => (
      // 앞으로 3가지 보드를 만들 것이다.
      <Board ref={magic.innerRef} {...magic.droppableProps}>
        {toDos.map((toDo, index) => (
         <DragabbleCard key={toDo} toDo={toDo} index={index} />
        ))}
        {magic.placeholder}
      </Board>
    )}
</Droppable>



이 부분을 잘라내주고

Components 폴더에 Board.tsx라는 새로운 컴포넌트를 만들어주고
붙여넣기 해준다.


<Board.tsx>
import 할 것들을 해주고 기존의 Board 컴포넌트는 이름이 겹치기 때문에 Wrapper로 고쳤다.
이렇게 하면 재사용할 수 있는 board 컴포넌트가 생겼다.

import { Droppable } from "react-beautiful-dnd";
import DragabbleCard from "./DragabbleCard";
import styled from "styled-components";

const Wrapper = styled.div`
  border-radius: 5px;
  background-color: ${(props) => props.theme.boardColor};
  padding: 20px 10px;
  padding-top: 30px;
  min-height: 200px;
`;

interface IBoardProps {
  toDos: string[];
  boardId: string;
}

// boardId를 넘겨주고 밑에서 DroppableId로 boardId를 주도록 한다.
function Board({ toDos, boardId }: IBoardProps) {
  return (
    <Droppable droppableId={boardId}>
      {(magic) => (
        // 앞으로 3가지 보드를 만들 것이다.
        <Wrapper ref={magic.innerRef} {...magic.droppableProps}>
          {toDos.map((toDo, index) => (
            <DragabbleCard key={toDo} toDo={toDo} index={index} />
          ))}
          {magic.placeholder}
        </Wrapper>
      )}
    </Droppable>
  );
}

export default Board;







<App.tsx>
App.tsx에서는 문제가 생겼는데
map을 못쓰게 되었기 때문에
object를 loop 할 방법을 찾아보아야 한다.

  return (
    <DragDropContext onDragEnd={onDragEnd}>
      <Wrapper>
        <Boards>
            // 이 부분을 render 해야 하는데 toDos에서 map을 못쓰게 됐음
        </Boards>
      </Wrapper>
    </DragDropContext>
  );
}

export default App;

 

 

해결할 방안을 생각해보자






나는 id를 이용해서 board를 만들거라서 value는 필요가 없다.




이제 이걸 응용해서 해보도록 한다.



<App.tsx>

Object.keys(toDos) 까지 하면 board의 모든 Id를 받아왔음.
그럼 그 boardId로 map을 이용해 새로운 board들을 만들어준다.

  return (
    <DragDropContext onDragEnd={onDragEnd}>
      <Wrapper>
        <Boards>{Object.keys(toDos).map((boardId) => <Board key={boardId} toDos={toDos[boardId]} boardId={boardId} />)}</Boards>
      </Wrapper>
    </DragDropContext>
  );
}

export default App;




<atom.tsx>

인터페이스를 만들어주고 적용해준다.

이렇게 만들지 않는다면 타입스크립트는 선택지를 to_do, doing, done 밖에 생각하지 않을 것이다.

후에 유저가 board를 만들 가능성도 열어두기 위해

이렇게 만들어 주도록 하겠다.

import { atom } from "recoil";

// interface를 하나 만든다
interface IToDoState {
  // 이 state는 string으로서의 property와, string array로 이루어져있다고 알려주겠음
  [key: string]: string[];
}

export const toDoState = atom<IToDoState>({
  key: "toDo",
  // default를 기존의 배열에서 -> object로 변경해준다.
  default: {
    to_do: ["a", "b"],
    doing: ["c", "d", "e"],
    done: ["f"],
  },
});




실행결과

3개의 보드가 만들어졌다.





Comments