TRELLO Clone #2 React-beautiful-dnd(2)

Leesu·2022년 12월 5일
0
  • 목표
    • 아이템을 drag and drop 했을 때 리스트들이 재정렬 될 수 있도록onDragEnd 함수 설정해주기
  • 그러기 위해 todo state 를 위한 atom 을 만들어줬다.
-- atoms.tsx

import { atom, selector } from "recoil";

export const toDoState = atom({
  key: "toDo",
  default: ["a", "b", "c", "d", "e", "f"],
});

onDragEnd

  • DragDropContext 컴포넌트는 onDragEnd라는 props를 받고,
    onDragEnd props 에 담기는 함수는 드래그가 끝날때 실행된다.
  • onDragEnd 함수의 첫번째 인자(result)에는 드래그 항목에 대한 정보가 담긴다.

  • draggableId: 드래그 되었던 Draggable의 id.
  • type: 드래그 되었던 Draggable의 type.
  • source: Draggable 이 시작된 위치(location).
  • destination: Draggable이 끝난 위치(location).
    (만약 Draggable이 시작한 위치와 같은 위치로 돌아오면 destination 값은 null이 된다.)
-- App.tsx

function App() {
  const [toDos, setToDos] = useRecoilState(toDoState);
  const onDragEnd = ({ destination, source }: DropResult) => {
	// DropResult : 
  };
  return (
    <DragDropContext onDragEnd={onDragEnd}>
      <Wrapper>
      ...
  • 리스트를 재정렬 하려면, drag 된 index 값을 가져와서, drop 된 index에 넣어주면 된다는 것을 알수이찌.
  • 그전에 typescript 에게 { destination, source } type 을 알려줬다.

  • 리스트를 재정렬 하려면 어떻게 해야할까?
    • array 로부터 source.index 를 지웠다가, destination.index 에 추가하기!

Array.prototype.splice()

  • 🚩 DOCS
  • splice() 메서드는 배열의 기존 요소를 삭제 또는 교체하거나 새 요소를 추가하여 배열의 내용을 변경한다.
  • 구문
array.splice(start[, deleteCount[, item1[, item2[, ...]]]])
  • start : 배열의 변경을 시작할 인덱스
  • deleteCount : 배열에 추가할 요소.
    (아무 요소도 지정하지 않으면 splice()는 요소를 제거하기만 한다.)
  • item1... : 배열에 추가할 요소.
    (아무 요소도 지정하지 않으면 splice()는 요소를 제거하기만 한다.)
  • 이제 splice() 를 사용해서 재정렬해주쟈
const onDragEnd = ({ draggableId, destination, source }: DropResult) => {
    if (!destination) return;
    // → 유저가 item 을 같은 자리에 둘 경우, destination 이 없을 경우
    setToDos((oldToDos) => {
      const toDosCopy = [...oldToDos];
      // 1) source.index에 있는 item 삭제하기
      toDosCopy.splice(source.index, 1);
      // 2) destination.index 로 item(draggableId)을 다시 추가하기
      toDosCopy.splice(destination?.index, 0, draggableId);
      return toDosCopy;
    });
  };
  return ( 
  .
  .
  .
  <Draggable key={toDo} draggableId={toDo} index={index}>
  • < Draggable /> list의 키

    • list를 렌더링하는 경우 각 < Draggable />에 key prop을 추가해야함
    • 규칙
      • key 는 list 내에서 고유해야함
      • key 에 item의 index가 포함되어서는 안됨! (map의 index사용 X)
      • 일반적으로 draggableIdkey로 사용하면 된다!
  • 그럼 이렇게 짜잔!!

f 를 a 의 자리로 옮겼다!

  • 콘솔로 과정을 확인해보자면
  const onDragEnd = ({ draggableId, destination, source }: DropResult) => {
    if (!destination) return;
    setToDos((oldToDos) => {
      const toDosCopy = [...oldToDos];
      // 1) source.index에 있는 item 삭제하기
      console.log("Delete item on", source.index);
      console.log(toDosCopy);
      toDosCopy.splice(source.index, 1);
      console.log("Deleted item");
      console.log(toDosCopy);
      // 2) destination.index 로 item(draggableId)을 다시 추가하기
      console.log("Put back", draggableId, "on ", destination.index);
      toDosCopy.splice(destination?.index, 0, draggableId);
      console.log(toDosCopy);
      return toDosCopy;
    });
  };

  • 어디서 움직임이 시작되고, 삭제&추가되었는지, board 의 id 는 무엇인지 보인다!

  • 추가로, 코드를 보면 index 등이 변경될 때마다 모든 card(draggble) 들을 다시 렌더링하고있다.

  • 그래서, 리스트들을 옮기는 과정에서 리스트를 다시 그려야하니 렌더링되며 텍스트가 흔들려보인다.

React.memo

React.memo는 고차 컴포넌트(Higher Order Component)입니다.
컴포넌트가 동일한 props로 동일한 결과를 렌더링해낸다면, React.memo를 호출하고 결과를 메모이징(Memoizing)하도록 래핑하여 경우에 따라 성능 향상을 누릴 수 있습니다.
즉, React는 컴포넌트를 렌더링하지 않고 마지막으로 렌더링된 결과를 재사용합니다.

  • React.memo는 props 변화에만 영향을 준다.

    • React.memo 를 쓰지 않는다면,
      DragbbleCard 의 부모 컴포넌트인 <Board />,<Droppable> 등의 state 가 변화하면, DraggableCard 는 매번 재렌더링된다는 말...🤔
  • 즉, 이 메서드는 오직 성능 최적화를 위하여 사용된다.

  • 우리는, DraggableCard에게 동일한 index 와 동일한 todo prop을 받으면 리랜더링을 하지 않도록 하기 위해 사용해준 것.

-- DragabbleCard.tsx

interface IDragabbleCardProps {
  toDo: string;
  index: number;
}

function DragabbleCard({ toDo, index }: IDragabbleCardProps) {
  console.log(toDo, "has been rendered");
  return (
    <Draggable key={toDo} draggableId={toDo} index={index}>
      {(magic) => (
        <Card
          ref={magic.innerRef}
          {...magic.dragHandleProps}
          {...magic.draggableProps}
        >
          {toDo}
        </Card>
      )}
    </Draggable>
  );
}

export default React.memo(DragabbleCard);  <<<---
-- App.tsx

import DragabbleCard from "./Components/DragabbleCard";

.
.
.

<DragabbleCard key={toDo} index={index} toDo={toDo} />
  • DONE!
  • 이렇게하면, index 의 값이 변화한 아이템들에 대해서만 렌더링이 된다!
  • c 와 f 의 위치를 바꾸고, 콘솔로 렌더링을 확인해보면...

  • 이제.. 여러개의 보드를 만들러 가보쟈 이게 젤 재밌을듯!!
profile
기억력 안 좋은 FE 개발자의 메모장

0개의 댓글