onDragEnd
함수 설정해주기-- atoms.tsx
import { atom, selector } from "recoil";
export const toDoState = atom({
key: "toDo",
default: ["a", "b", "c", "d", "e", "f"],
});
DragDropContext
컴포넌트는 onDragEnd
라는 props
를 받고,onDragEnd
props
에 담기는 함수는 드래그가 끝날때 실행된다. onDragEnd
함수의 첫번째 인자(result)에는 드래그 항목에 대한 정보가 담긴다.-- App.tsx
function App() {
const [toDos, setToDos] = useRecoilState(toDoState);
const onDragEnd = ({ destination, source }: DropResult) => {
// DropResult :
};
return (
<DragDropContext onDragEnd={onDragEnd}>
<Wrapper>
...
index
값을 가져와서, drop 된 index
에 넣어주면 된다는 것을 알수이찌.{ destination, source }
type 을 알려줬다.source.index
를 지웠다가, destination.index
에 추가하기!splice()
메서드는 배열의 기존 요소를 삭제 또는 교체하거나 새 요소를 추가하여 배열의 내용을 변경한다.array.splice(start[, deleteCount[, item1[, item2[, ...]]]])
start
: 배열의 변경을 시작할 인덱스deleteCount
: 배열에 추가할 요소.item1...
: 배열에 추가할 요소.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의 키
index
가 포함되어서는 안됨! (map의 index사용 X)draggableId
를 key
로 사용하면 된다!그럼 이렇게 짜잔!!
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는 고차 컴포넌트(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} />