토글 핸들링
2022. 1. 3. 21:43
반응형
위에 보이는 것 처럼 토글 스위치를 켜면 아래 로그차트에 공부한 시간이 기록되는 것을 시각화 해주어야 한다. 그러기 위해서는 토글을 켜고 끌 수 있는 로직을 만들어야하고, 두개 이상이 동시에 켜지면 안되도록 해줘야 한다. 이 기능을 구현하는 과정을 기록해보고자 한다.
토글 디자인을 다 마치고 토글을 켜고 끄는 로직, 하나 켜져있는 상태에서 다른 토글을 키려고 할 때 켜져있던 것을 꺼지도록 해주는 로직을 만드는 과정에서 문제가 생겼다.
어떤 문제인가요?
- 기본적으로 하나의 토글을 켜면 다른 토글은 꺼져야한다.
- 하나의 토글을 켜면 다른 토글은 꺼지는 것이 구현은 되었으나, 해당 토글만 켰다 끄려고 할 때 끄는게 안된다.
현재 코드
const [toggleBox, setToggleBox] = useState([
{ name: "휴식", isOn: true, color: "#a5c7e5" },
]);
const toggleHandler = (idx) => {
// 토글이 켜져있는 것만 골라서 담아준다.
const numOfIsOn = toggleBox.filter((el) => el.isOn === true);
// 토글이 한개 켜져있는 상태에서 다른 토글을 키려고 하는 경우 모든 토글을 다 끄고 해당 토글만 킨다.
if (numOfIsOn.length > 0) {
const allOff = toggleBox.map((el) => ({ ...el, isOn: false }));
allOff[idx].isOn = !allOff[idx].isOn;
setToggleBox(allOff);
// 위의 경우가 아닐경우. 즉, 하나만 켜고 끌때
} else {
const newToggleBox = [...toggleBox];
newToggleBox[idx].isOn = !newToggleBox[idx].isOn;
setToggleBox(newToggleBox);
}
};
- 함수가 한 박자 느리게 작동하는 것 같다. 토글을 눌렀을 때 함수 안에있는 로직들이 작동하면서 한 박자 느리게 작동하는 것 같다. 예를 들어서, 초기 상태에서 휴식 토글을 켜면 numOfIsOn은 빈배열이기 때문에 else로 들어오고 제대로 잘 켜진다. 그 다음 영어 토글을 켜면, numOfIsOn은 휴식토글을 가지고 있고, 그렇기 때문에 첫 번째 조건으로 들어와 토글을 다 끄고 영어 토글만 켠다. 근데 이때 다시 영어 토글을 눌러 끄려고 하면 첫 번째 조건으로 들어와 전부 꺼준뒤 다시 켜주기 때문에 계속 켜져있는 상태가 된다.
- 문제가 발생한 원인을 다시 천천천히 훑어보니 함수가 한 박자 느린건 아니었고, 느리게 작동하고 있는 것도 아니었다. 위의 로직대로라면 하나의 토글이 켜져있고, 다시 그 토글을 눌러서 끄려고하면 allOff[idx].isOn = !allOff[idx].isOn; 이 부분 때문에 다시 켜라고 하고 있기 때문에 그대로 켜져있게 되는 것이었다.
해결 방법
- 조건을 나눠서 적용하니 해결할 수 있었다. 즉, 켜져있는 토글을 다시 끄려고 할 때 allOff[idx].isOn = !allOff[idx].isOn; 으로 다시 켜지않게 조건을 나눠주었다.
const [toggleBox, setToggleBox] = useState([
{ name: "휴식", isOn: true, color: "#a5c7e5", id: 0 },
]);
// 토글을 추가하는 함수
const editCompleteHandler = () => {
// 토글을 추가해줄 때 id값을 새로 만들어줬는데, 사실 여기서 만들어 줄 필요가 없다.
// 왜냐하면 데이터베이스에서 받아오는 id를 사용하면 되기 때문이다. 이 때는 아직 데이터베이스와 연결되어있지 않아서
// 만들면서 실험해보기 위해서 직접 id값을 만들어주었다.
const num = toggleBox[toggleBox.length - 1].id + 1;
setToggleBox([
...toggleBox,
{ name: inputValue, isOn: false, color: pickedColor, id: num },
]);
setPlusClick(false);
setPickedColor("lightgrey");
setInputValue("공부"); };
const toggleHandler = (idx) => {
// 토글이 켜진 것만 골라서 담아준다.
const numOfIsOn = toggleBox.filter((el) => el.isOn === true);
// 토글이 한 개 켜져있는 상태에서 다른 토글을 키려고 하는 경우 모든 토글을 다 끄고 해당 토글만 킨다.
if (numOfIsOn.length > 0) {
const allOff = toggleBox.map((el) => ({ ...el, isOn: false }));
// 사실 numOfIsOn이 켜져있는 토글을 모두 찾은 배열이지만, 한 개 이상 생기면 allOff가 다 끄기 때문에 켜지는 토글이 두 개 이상 생길 수가 없다.
// 그래서 현재 켜져있는게 내가 누른 토글이라면, 그냥 끄도록 만든 조건이다.
if (numOfIsOn[0].id === toggleBox[idx].id) {
setToggleBox(allOff);
} else {
allOff[idx].isOn = !allOff[idx].isOn;
setToggleBox(allOff);
}
// 전부 다 꺼져있는 상황을 위해 필요하다.
} else {
const newToggleBox = [...toggleBox];
newToggleBox[idx].isOn = !newToggleBox[idx].isOn;
setToggleBox(newToggleBox);
}
};
최종버전
- API 요청이 추가되었고, 조금 더 알아보기 쉽도록 변수명을 변경해준 완성본이다.
function SideLog() {
// 로그인이 되어있다면, 서버에서 본인이 가지고 있는 토글 정보를 받아와서 toggles 상태에 넣어줄 것이다.
const [toggles, setToggles] = useState([]);
const toggleHandler = (idx) => {
// 켜져있는 토글을 찾는다.
const turnedOn = [...toggles].filter((toggle) => toggle.isOn === 1);
// 켜져있는 토글이 있으면
if (turnedOn.length > 0) {
// 다 끈 토글을 담아둔다.
const turnOffAll = [...toggles].map((toggle) => ({ ...toggle, isOn: 0 }));
// 하나 켜져있는 상태에서 같은 토글을 눌러 꺼줄 때
if (turnedOn[0].id === toggles[idx].id) {
logAPI.finishLog(turnedOn[0].id); // 기록 중지하라는 API 요청
setToggleBox(turnOffAll);
}
// 토글 하나 켜져있고, 다른 토글 바로 켤 때
else {
// 켜져있던 토글 기록 끝내라고 요청
const finishedToggle = turnedOn[0];
logAPI.finishLog(finishedToggle.id);
// 다 끈 토글 중에서 클릭한 토글만 다시 켠다.
const clickedToggle = turnOffAll[idx]
clickedToggle.isOn = 1;
setToggles(turnOffAll);
logAPI.initiateLog(clickedToggle.id); //기록 시작하라는 API 요청
}
}
// 켜져있는 토글이 없으면
else {
const newToggles = [...toggles];
const clicked = newToggles[idx]
clicked.isOn = 1;
setToggleBox(newToggles);
logAPI.initiateLog(clicked.id);
}
};
//중략
}
보완할 점
- 로그아웃 안하고 창을 껐을 때 기록이 중지 될 수 있도록 토글을 꺼줄 수 있는 방법을 찾아서 적용하기.
완성본
반응형
LIST
'코드스테이츠 수강 TIL > Final Project' 카테고리의 다른 글
final_project DAY+7 (0) | 2022.01.04 |
---|---|
final_project DAY+6 (0) | 2022.01.03 |
final_project DAY+5 (0) | 2022.01.03 |
final_project DAY+4 (0) | 2022.01.03 |
final_project DAY+3 (0) | 2022.01.03 |