taskgrow 프로젝트에서 할 일 리스트를 유저가 중요도에 따라 자유롭게 순서를 변환할 수 있도록 UX 개선이 필요하다.
불필요한 리렌더링을 줄이기 위해 useRef를 사용해서 구현했다.
순서를 바꾸는 구현에 있어 생각이 많았다.
단순한 것이지만 드래그라 쉽게 변경 가능함 -> 많은 요청 으로 유저가 최종적으로 수정을 마친 후 한 번만 요청을 보낼 수 있도록 생각을 해보았지만..
- 클라이언트에서 순서 저장해두고 있다가 해당 테스크를 벗어나면 변경된 order 서버에 요청 -> 순서 옮기고 브라우저 창을 닫으면 적용 안됨
- 순서 변경 버튼 생성 -> 버튼 클릭 후 자유롭게 순서 변경 가능 -> 확인 버튼 클릭시 변경된 order 서버에 요청 -> 유저 번거로움
와 같은 문제로 딱히 좋은 방법이 떠오르지 않았다.
그래서 기존에 많은 요청을 보낼까봐 걱정했던 게 사실 별 거 아닌 성능 이슈였나 싶기도 하여 우선 드래그시 바로 순서 변경을 할 수 있도록 했다.
const dragItemOrderNo = useRef<number>(0);
const dragItemTodoId = useRef<number>(0);
const dragOverItemOrderNo = useRef<number>(0);
const dragOverItemTodoId = useRef<number>(0);
무조건적으로 값이 들어가기 때문에 0으로 초기화를 해줬다.
순서 변경 API 요청을 해야하기 때문에 현재 변경할 할 일의 순서와 id, 변경될 할 일의 순서와 id를 받아올 수 있도록 했다.
<li
key={todo.todoId}
onDragStart={() => handleDragStart(todo.orderNo, todo.todoId)}
onDragEnter={() => handleDragEnter(todo.orderNo, todo.todoId)}
onDragEnd={(e) => drop(e)}
draggable
>
<Todo ... />
</li>
할 일 내용인 Todo를 li로 감싸주고 드래그가 가능하도록하여 드래그 시작, 드래그 진행중, 드래그 끝남 각 인지할 수 있도록 작성했다.
여기서 드래그가 해당 할 일 리스트에만 두었을 때 순서를 변경할 수 있도록 해야하는데 할 일 리스트 영역 외에 다른 곳에 두었을 때 마지막으로 인식된 곳의 순서와 id가 저장되어서 거기로 바뀌는 문제가 있었다. (예 : 1번째 순서인 할 일을 드래그해서 2번째 순서인 할 일을 거침 그리고 할 일 리스트 영역이 아닌 다른 곳에 드래그를 놓음 -> 2번째를 마지막으로 거쳤기 때문에 2번째랑 교환이 됨)
할 일 리스트가 아닌 곳에 드래그를 놓으면 다시 원래 상태로 가야하는데 마지막으로 기록된 2번째랑 교환이 되는 문제점이 발생했다.
이를 해결하기 위해 할 일 리스트 영역을 벗어나면 순서가 바뀌지 않도록 해야했는데 할 일 리스트를 벗어났을 때 생기는 이벤트함수는 찾을 수가 없었다 (찾지 못한걸수도 있다.)
그래서 마우스가 드랍된 x,y좌표를 찾아내고 할 일 리스트의 top, bottom, left, right 좌표를 찾아내서 그 안에 드랍됐을 때만 정상적으로 할 일의 순서가 바뀌도록 작성했다.
const x = e.clientX;
const y = e.clientY;
const tasksElement = document.getElementById('task');
const rect = tasksElement!.getBoundingClientRect();
const top = rect.top;
const bottom = rect.bottom;
const left = rect.left;
const right = rect.right;
그리고 또 생긴 문제..
단순히 드래그된 할 일과 드랍 대상인 할 일과 순서만 변경된다고 생각했는데 직접 실행해보니 뭔가 어색했다.
생각해보니 둘만 순서가 변경되는 게 아니라 순서가 밀려야한다.
(1,2,3,4,5에서 2를 드래그해서 5에 자리에 두면 1,3,4,5,2가 되어야함)
그래서 순서가 위인 것을 아래로 옮기면 뒤로 오고, 순서가 아래인 것을 위로 옮기면 위로 올라가도록 변경했다.
// 해당 task의 모든 todo를 불러옴
const todos: Todo[] = await getTodos(selectedTaskId);
// dragTodo의 orderNo 뒤부터 ~ dragOverTodo의 orderNo 전까지
if (dragTodoOrderNo < dragOverTodoOrderNo) {
todos.forEach((todo) => {
if (
todo.orderNo > dragTodoOrderNo &&
todo.orderNo <= dragOverTodoOrderNo
) {
updateTodoOrder(todo.todoId, todo.orderNo - 1);
}
});
} else {
todos.forEach((todo) => {
if (
todo.orderNo < dragTodoOrderNo &&
todo.orderNo >= dragOverTodoOrderNo
) {
updateTodoOrder(todo.todoId, todo.orderNo + 1);
}
});
}
생각한대로 짜느라 코드가 좋지 못한 거 같다.. 이건 추후 개선 사항
그렇게 해서 만든 아래와 같은 할 일 리스트의 순서 변경
부자연스러워서 더 자연스럽게 UI/UX 개선사항이 필요할 거 같다.
이것 또한 현재 프로젝트에서 중요하지 않으니 추후 개선 사항
간단하다고 생각했는데 구현하다보니 로직을 짜거나 고려해야할 점이 많았다.
'Programming > React' 카테고리의 다른 글
시간에 따라 달라지는 HTML title과 favicon 만들기 (3) | 2024.02.04 |
---|---|
[React-Query] kakao tech, 우아한테크세미나를 보고나서.. (0) | 2023.08.18 |
[디자인 패턴] 아토믹 디자인(Atomic Design) (0) | 2023.08.13 |
[React] CRA가 아닌 Vite로 React 시작하기 (0) | 2023.08.10 |