Drag And Drop : DND 앱
CRA > `react-beautiful-dnd`
드래그앤드랍을 위한 라이브러리
- <DragDropContext /> : 사용하고 싶은 부분 전체를 감싸는 wrap
- <Droppable /> : 드래그 떨굴 수 있는 부분
- <Draggable /> : 드래그 할 아이템
+ provied + {...provided.droppableProps} + ref={provide.innerRef} > 스타일 및 조회를 위한 속성!
import "./App.css";
import { useState } from "react";
import { DragDropContext, Draggable, Droppable } from "react-beautiful-dnd";
const finalSpaceCharacters = [
{
id: "gary",
name: "Garry Goodspeed",
},
{
id: "cato",
name: "Little Cato",
},
{
id: "kvn",
name: "KVN",
},
];
function App() {
const [characters, setCharacters] = useState(finalSpaceCharacters);
return (
<div className="App">
<header className="App-header">
<h1>Final Space Characters</h1>
<DragDropContext onDragEnd={handleEnd}>
<Droppable droppableId="characters">
{(provided) => (
<ul
className="characters"
{...provided.droppableProps}
ref={provided.innerRef}
>
{characters.map(({ id, name }, index) => {
return (
<Draggable key={id} droppableId={id} index={index}>
{(provided) => (
<li
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
>
<p>{name}</p>
</li>
)}
</Draggable>
);
})}
{provided.placeholder}
</ul>
)}
</Droppable>
</DragDropContext>
</header>
</div>
);
}
export default App;
사용자가 요소를 드래그 하는 경우 className 속성을 selected로 변경하고, 나중에 스타일을 적용하는데 사용한다.
placeholder 속성은 목록에 빈 공간을 만들어 드래그 작업이 저연스럽게 느껴지게 된다.
result 매개변수에는 souce 항목 및 대상 위치와 같은 드래그 이벤트에 대한 정보가 포함된다.
*리액트에서 state는 불변성을 지켜줘야 한다 > 메소드 Array.from
const handleEnd = (result) => {
if (!result.destination) return;
const items = Array.from(characters);
const [reorderedItem] = items.splice(result.source.index, 1);
items.splice(result.destination.index, 0, reorderedItem);
setCharacters(items);
};
//...
<DragDropContext onDragEnd={handleEnd}>
- 예외로 목적지가 없으면(드래그가 영역 밖에 되는 경우) 이 함수를 종료한다.
- 불변성을 지키는 새로운 데이터 items 생성
- 변경시키는 아이탬을 splice로 배열에서 지우고, 그 값을 reorderedItem 에 저장한다
- 원하는 자리에 reforderedItems 를 insert 해준다.
**이때 react 18의 StrictMode에서는 이전 버전들과 다르게 디버깅 목적을 위해 라이프사이클을 의도적으로 두 번 실행시키는데, 그 부분에서 등록된 Droppable의 ref 자체가 사라지는 이슈 === DroppableId를 찾지 못하는 에러가 발생했다.
간단하게 StrictMode 를 지워도 되지만(얘는 전에도 자꾸 두번호출해서 홧김에 지워버렸었는데ㅋㅋ) 개발 과정에서 버그를 찾을 수 있도록 도와줘서 제거하는게 좋은 선택지는 아니라고 멘토님께서 말씀해주셨다... 반성...
requestAnimationFrame을 사용해 컴포넌트가 렌더링 된 후 에 컴포넌트르 등록했다 > 1차 렌더링 후 paint 이후에 등록하는 방식이다.
브라우저에서 화면의 새로 고침 주기에 맞춰 콜백 함수를 호출하는 메서드이다. 컴포넌트가 첫 번째 렌더링을 완료한 후에 설정이 이루어지게 한다.
> Droppable 컴포넌트를 한번 렌더링 된 후에 렌더링 되도록 컴포넌트를 조건부 렌더링으로 감싼다.
///..
<DragDropContext onDragEnd={handleEnd}>
{isDroppableReady && (
<Droppable droppableId="characters">
{(provided) => (
<ul
//...
DND 플젝에 적용하기!
requestAnimationFrame을 사용해야 하는줄 알고 고민 많이 했는데,, 드래그 컴포넌트 나눠서 props로 값 전달해주는 방식은 에러가 발생하지 않네..?
app.tsx 에서 함수 선언
const handleDragEnd = (result: any) => {
const { destination, source, draggableId } = result;
const sourceList = lists.filter(
(list) => list.listId === source.droppableId
)[0];
dispatch(
sort({
boardIndex: boards.findIndex(
(board) => board.boardId === activeBoardId
),
droppableIdStart: source.droppableId,
droppableIdEnd: destination.droppableId,
droppableIndexStart: source.index,
droppableIndexEnd: destination.index,
draggableId: draggableId,
})
);
boardsSlice.ts 에서 인덱스 옮겨지는 기능 생성
sort: (state, { payload }: PayloadAction<TSortAction>) => {
//same list
if (payload.droppableIdStart === payload.droppableIdEnd) {
const list = state.boardArray[payload.boardIndex].lists.find(
(list) => list.listId === payload.droppableIdStart
);
//변경시키는 아이템을 배열에서 지워주고 + 리턴값으로 지워진 아이템 가져와서 + 넣어준다.
const card = list?.tasks.splice(payload.droppableIndexStart, 1);
list?.tasks.splice(payload.droppableIndexEnd, 0, ...card!);
}
//other list
if (payload.droppableIdStart !== payload.droppableIdEnd) {
const listStart = state.boardArray[payload.boardIndex].lists.find(
(list) => list.listId === payload.droppableIdStart
);
const card = listStart!.tasks.splice(payload.droppableIndexStart, 1);
const listEnd = state.boardArray[payload.boardIndex].lists.find(
(list) => list.listId === payload.droppableIdEnd
);
listEnd?.tasks.splice(payload.droppableIndexEnd, 0, ...card);
}
},
로그인 기능 > Firebase 구글 로그인
Firebase 구글 서비스 제공
Go to console > 프로젝트 추가 > 애널리스트 등록
로그인 하면 > Redux Store에 유저 데이터 넣기
firebase-tools 배포
`npm i -g firebase-tools`
`firebase login` > Success! Logged in as cdh010126r@gmail.com
리액트 src > build 파일 `npm run build` > dist 폴더를 이용해 배포
`firebase init`