팀 프로젝트로 듀얼 셀렉터를 구현하게 되었다.
내가 맡은 부분은 아이템을 왼쪽, 오른쪽으로 옮기는 기능이었다.
contorl+Click을 하면 아이템을 추가로 선택을 할 수 있게 해야하고, shift+Click을 누르면 시작부터 끝까지 선택되게 구현해야 했다.
선택한 아이템의 클릭 로직 부터 구현하였다.
// 선택된게 하나도 없으면 추가
if (selectId.length === 0) {
setSelectId([id]);
return;
}
// 이미 있는 아이디 일 시
if (selectId.findIndex((item) => item === id) !== -1) {
let data = [];
if (selectId.length !== 1) {
data = (prev) => prev.filter((element) => element !== id);
}
setSelectId(data);
} else {
setSelectId([id]);
}
일단 선택이 되면 선택된 아이테의 id값을 추가 하였고, 이미 존재하는 아이디이면 삭제를 하였다.
그 후, 선택된 아이디 값을 이용하여 해당하는 데이터를 옮기는 코드를 구현하였다.
// Left -> Right
if (direction) {
let copyData = Object.assign([], leftData);
selectId.map((id) =>
leftData.map((data) => {
if (id === data.id) {
copyData.splice(
copyData.findIndex((item) => item.id === id),
1
);
moveItem = [...moveItem, { ...data }];
}
})
);
setLeftData(copyData);
setRightData((prev) => [...prev, ...moveItem]);
}
왼쪽의 데이터에서 선택된 아이디를 삭제하고 오른쪽 데이터에 옮겨 주었다.
마지막으로 여러개의 아이템을 선택하는 로직을 구현하였다.
데이터 이동구현 시 여러개의 아이템이 들어왔을 때 도 고려하여 작성하였기 때문에 클릭 이벤트만 수정하여 구현을 마무리 하였다.
if (selectedNum && e.shiftKey) {
let copyData = Object.assign([], list);
let select = [];
const start = firstClick < idx ? firstClick : idx;
const end = firstClick < idx ? idx : firstClick;
copyData.slice(start, end + 1).map((item) => select.push(item.id));
setSelectId(select);
return;
}
e.shiftKey를 이용하면 shiftkey의 입력을 확인할 수 있다.
첫 클릭 인덱스를 기억해 두고 쉬프트 클릭이 들어왔을 때, 두 인덱스를 비교하여 음수값이 나오지 않도록 범위를 지정하였고, 지정된 범위의 id를 selectId로 등록 하였다.
if (selectedNum && e.ctrlKey) {
setFirstClick(idx);
setSelectId((prev) => [...prev, id]);
return;
}
컨트롤도 쉬프트와 마찬가지로 e.ctrlKey를 이용하여 구현하였다. 컨트롤 클릭 시 계속 selectId를 추가하도록 구현하였다.
어렵지 않은 기능 구현이었지만, 생각지도 못한 에러를 경험하였다.
아래의 코드는 아이템의 이동을 구현했던 오류가 발생했던 코드이다.
if (direction) {
let moveItem = [];
setLeftData((prev) => {
let copyData = Object.assign([], prev);
selectId.map((id) =>
leftData.map((data, index) => {
if (id === data.id) {
leftData.splice(index, 1);
moveItem = [...moveItem, data];
}
})
);
return copyData;
});
// moveItem --> null
setRightData((prev) => [...prev, ...moveItem]);
}
로컬 환경에서는 잘 동작했던 코드가 배포가 된 후 제대로 동작하지 않았다.
오류의 이유는 setState의 동작이 비동기이기 때문에 발생한 오류였다.
평소 데이터 업데이트 시 콜백을 이용하여 값을 업데이트 하였다.
위 코드에서 선택된 id를 담아서 오른쪽으로 넘겨 주어야 하는데
setState의 동작이 비동기이기 때문에 setLeftData에서 moveItem이 만들어지기도 전에 setRightData가 동작하여 moveItem은 비어있는 값이 되서 발생한 오류였다.