토글 핸들링

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

BELATED ARTICLES

more