일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 알고리즘 #프로그래머스 #코딩테스트 #자바스크립트
- useRef
- javascript
- 리액트
- React
- 위상정렬
- 자바스크립트
- 스티커
- react-beautiful-dnd
- 프로그래머스 #알고리즘 #자바스크립트
- 리코일
- usedebugvalue
- 타입스크립트
- recoil
- 훅
- 완전탐색
- Suspense
- useContext
- 백준 #알고리즘 #자바스크립트
- 백준
- 덕타이핑
- 드래그앤드롭
- 알고리즘 #코딩테스트 #프로그래머스 #자바
- 알고리즘
- 프로그래머스
- 다이나믹프로그래밍
- useLayoutEffect
- Today
- Total
몽환화
[React] react-beautiful-dnd 간단하게 시작해보기 본문
사실 이번에는 물고뜯기까지는 못하고 앙 물어보기만 해서 물고뜯기라고 못함 그냥 시작해보자고
모종의 이유로 드래그앤드롭을 활용할 일이 매우 많아졌습니다.. 그리고 주로 사용하는 라이브러리가 바로 이
react-beautiful-dnd 였기에 공부를 해보았어요
사실 냅다 적용부터 해보고 뒤늦게 공부중;
이럴줄 알았으면 토이플젝때 투두리스트 내가맡을걸!
아무튼 시작
https://github.com/atlassian/react-beautiful-dnd
GitHub - atlassian/react-beautiful-dnd: Beautiful and accessible drag and drop for lists with React
Beautiful and accessible drag and drop for lists with React - atlassian/react-beautiful-dnd
github.com
https://www.npmjs.com/package/react-beautiful-dnd/v/11.0.2
react-beautiful-dnd
Beautiful and accessible drag and drop for lists with React. Latest version: 13.1.1, last published: 2 years ago. Start using react-beautiful-dnd in your project by running `npm i react-beautiful-dnd`. There are 2012 other projects in the npm registry usin
www.npmjs.com
이 라이브러리는 무려 아틀라시안에서 만든것이다
믿고 써도 된다는 뜻!
npm i react-beautiful-dnd @types/react-beautiful-dnd
몇번 써보면 금방 적응될 것 같긴 한데 처음 건드리기가 상당히 복잡하고 어렵다
그래서 정말 간단한 예제를 들어볼 예정!
https://github.com/LeeHyungGeun/react-beautiful-dnd-kr
한국어로 번역해주신 Docs도 있당!
먼저 드래그앤드롭이 뭐냐
-드래그
-드롭
두가지가 필요하다
원하는 요소를 먼저 집어서 옮기고 내려놓는 과정이 필요하다
이걸 beautiful-dnd에서 적용하려면
집어서 옮기고 => draggable
내려놓는 => droppable
이 되겠다.
여기서 유의할 점은 만약 투두리스트같은 일반 리스트 dnd를 할거라면
결국 집는 요소나 내려놓는 요소나 그 위치가 그 위치라는거
droppable한 곳에서 다시 집어서 옮겨야하니 draggable 해야 한다
물론 이런건 자신이 어떤 드래그앤드롭을 구현하냐에 따라 달라지겠지만!
아무튼 저 두 개념을 알고 시작하면 되겠다.
그리고 중요한 요소 세개
DragDropContext
우리가 드래그앤드롭을 할 전체 공간을 감싸줘야한다. 익숙한 context의 등장.
사용할 컴포넌트의 전체를 감싸주면 된다
이 내부에 앞서 말한 Draggable과 Droppable을 적용하면 된다
Droppable
앞서 설명한 요소를 내려놓을 수 있는 공간, 내려놓은 곳에서 다시 집어서 옮기려면 다음의 Draggable을 포함한다.
Draggable
집어서 옮길 수 있는 요소들.
이렇게 크게 세가지 요소를 알면 된다.
조금 더 자세히 알아보자면
DragDropContext
onDragEnd : DragDropContext의 필수함수
말 그대로 드래그가 종료되었을 때 발생할 일을 담아주어야 한다.
react-beautiful-dnd will throw an error if a onDragEnd prop is not provided
This function is extremely important and has an critical role to play in the application lifecycle. This function must result in the synchronous reordering of a list of Draggables
onDragStart :
onDragEnd처럼 필수함수는 아니지만 드래그가 시작될 때 발생할 일을 담아줄 수 있다.
Droppable
<Droppable /> components can be dropped on by a <Draggable />. They also contain <Draggable />s. A <Draggable /> must be contained within a <Droppable />.
droppableId
스트링으로 지정해야하고 드롭 가능한 곳을 구분해주기 위한 id이다
provided
provided.innerRef 를 ref에 걸어준다. 드래그앤드롭은 결국 돔을 조작하는 일이기 때문에 설정해주어야 한다. 그래야 얘를 바로 찾아서 조작해줄 수 있다
provided.droppableProps 이것두
provided.placeholder drop될 때 영역을 미리 잡아놓는 역할을 한
snapshot 필수요소는 아니고 드래그앤드롭할때 스타일을 설정해줄 수 있다.
Draggable
draggableId
마찬가지로 드래그할 영역을 구분할 id
index
반드시 순서대로 입력되어야함!
provided
provided.innerRef 이건 위에랑 똑같고
provided.draggableProps 이것도 등록해주기위해 필요하다
provided.dragHandleProps
snapshot : 마찬가지
그럼 대충 요소들의 역할을 알겠고 이걸 어떻게 적용할건데?
이 드래그앤드롭은 결국 단순히 드래그하고 드롭하고 끝나는게 아니라 드래그앤드롭을 통해서 우리에게 보여지는 요소들의 위치, 순서를 바꿔주어야 한다. 이것이 onDragEnd함수에 담길 내용이다!
그걸 어떻게 담냐
간단한 예시를 보자
<DragDropContext onDragEnd={onDragEnd}>
<Droppable droppableId="01" key="01">
{(provided, snapshot) => (
<DraggableBox ref={provided.innerRef} {...provided.droppableProps}>
{list.map((babo, index) => (
<Draggable key={babo.id} draggableId={babo.id} index={index}>
{(provided) => (
<DraggablePoint
ref={provided.innerRef}
{...provided.dragHandleProps}
{...provided.draggableProps}
>
{babo.content}
</DraggablePoint>
)}
</Draggable>
))}
{provided.placeholder}
</DraggableBox>
)}
</Droppable>
</DragDropContext>
위의 내용을 적용하면 이렇게 표시할 수 있다 DraggableBox랑 DraggablePoint는 그냥 내가 스타일 컴포넌트 먹인거고
Droppable요소 안에 Draggable이 들어가있다는걸 확인하자
물론 이렇게 보면 뭔지 모르겠다... babo가 뭔냐면
자 바보 세명이 있다 쿄쿄
const [list, setList] = useState([
{ id: "babo1", content: <h3>바보1</h3> },
{ id: "babo2", content: <h3>바보2</h3> },
{ id: "babo3", content: <h3>바보3</h3> },
]);
const onDragEnd = (result: DropResult) => {
if (!result?.destination) return;
console.log(result);
const sourceIndex = result.source.index;
const destinationIndex = result.destination.index;
const newList = [...list];
const pickedBabo = newList[sourceIndex];
newList.splice(sourceIndex, 1);
newList.splice(destinationIndex, 0, pickedBabo);
setList(newList);
};
useState를 사용해 초기 상태를 설정해준다
결국 얘네도 상태관리가 필요한 놈들이니까
다만 우리에게 필요한 id를 설정하고, 각 바보들의 컨텐츠를 돔 요소로 담아줘보자
onDragEnd 함수를 찬찬히 살펴보면 얘는 DropResult라는 타입으로 result를 받는데
이 result는 크게 destination과 source를 받는다.
result.destination이 없다는건 목적지가 없다 => 요상한 곳으로 드래그를 시켰다는 뜻이니 return시켜 없던일로 만든다
즉 초기 상태로 돌려놓는다.
..콘솔은 테스트한다고 그냥 찍어본거고
이렇게 요소들을 담고있다
draggableId와 destination에 해당하는 droppableId, index를 모두 갖고있으니 이것들을 통해서 드래그된 이후의 액션을 설정하면 된다.
const sourceIndex = result.source.index;
const destinationIndex = result.destination.index;
result.source 는 말 그대로 소스. 내가 드래그를 해 온 요소를 가리킨다.
result.destination 은 목적지. 내가 드래그앤드롭한 목적지를 가리킨다.
각 요소의 index를 먼저 뽑아오자.
우리의 목적은 해당 두 요소의 위치를 바꿔주는거다!
const newList = [...list];
const pickedBabo = newList[sourceIndex];
newList.splice(sourceIndex, 1);
newList.splice(destinationIndex, 0, pickedBabo);
초기 list 상태를 복사하고, 드래그를 해 온 요소를 pickedBabo에 저장한다.
복사한 리스트에서 sourceIndex부분을 삭제한 뒤 저장한 pickedBabo를 붙여넣는다.
그럼 두 위치가 바뀌었겠지?
이걸 list에 다시 저장하면 되는거다.
이게 기본적인 투두리스트 같은 예제에서 드래그앤드롭을 하는 예시일거다.
코드 전문
import { useState } from "react";
import {
DragDropContext,
Draggable,
Droppable,
DropResult,
} from "react-beautiful-dnd";
import styled from "styled-components";
export const Dnd = () => {
const [list, setList] = useState([
{ id: "babo1", content: <h3>바보1</h3> },
{ id: "babo2", content: <h3>바보2</h3> },
{ id: "babo3", content: <h3>바보3</h3> },
]);
const onDragEnd = (result: DropResult) => {
if (!result?.destination) return;
console.log(result);
const sourceIndex = result.source.index;
const destinationIndex = result.destination.index;
const newList = [...list];
const pickedBabo = newList[sourceIndex];
newList.splice(sourceIndex, 1);
newList.splice(destinationIndex, 0, pickedBabo);
setList(newList);
};
return (
<div>
<DragDropContext onDragEnd={onDragEnd}>
<Droppable droppableId="01" key="01">
{(provided, snapshot) => (
<DraggableBox ref={provided.innerRef} {...provided.droppableProps}>
{list.map((babo, index) => (
<Draggable key={babo.id} draggableId={babo.id} index={index}>
{(provided) => (
<DraggablePoint
ref={provided.innerRef}
{...provided.dragHandleProps}
{...provided.draggableProps}
>
{babo.content}
</DraggablePoint>
)}
</Draggable>
))}
{provided.placeholder}
</DraggableBox>
)}
</Droppable>
</DragDropContext>
</div>
);
};
const DraggableBox = styled.div`
display: flex;
flex-direction: column;
`;
const DraggablePoint = styled.div`
display: flex;
justify-contents: center;
height: 50px;
`;
만약 드래그앤드롭이 잘 되지 않고 항목이 선택이 잘 안된다면 리액트의 strickmode를 해제해보자
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { RecoilRoot } from "recoil";
const root = ReactDOM.createRoot(
document.getElementById("root") as HTMLElement
);
root.render(
<RecoilRoot>
{/* <React.StrictMode> */}
<App />
{/* </React.StrictMode> */}
</RecoilRoot>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
dnd를 사용한 진짜 간단한 예제이다 이제 이걸 가지고 다양하게 변형해 적용하면 된다!
예를들면 내가 지금 하고있는 컨텐츠 제작이라든ㄱ ㅏ,,,등등
'Front > React' 카테고리의 다른 글
[React] Suspense 사용해보기 (0) | 2025.04.20 |
---|---|
[React] Recoil 뜯어보기 (0) | 2024.05.22 |
[React] useLayoutEffect, useDebugValue (0) | 2024.05.06 |
[React] useImperativeHandle 물고뜯기 (0) | 2024.05.06 |
[React] useReducer 물고뜯기 (0) | 2024.05.03 |