이번 섹션을 끝내기 전에
이 앱에 추가할 마지막 기능이 하나 남았습니다
이 기능은 항목을 삭제했을 때
열리는 이 모달과 연관이 있습니다
아시다시피 여기에는 설정된 타이머가 존재합니다
이 모달이 열렸을 때 시작되는 타이머인데
이로 인해 3초 뒤에 창이 닫히고 항목이 제거됩니다
그러나 지금 문제는
그러한 타이머가 있다는 것을 사용자에게 고지하고 있지 않습니다
그래서 사용자가 놀랄 수도 있습니다
갑자기 창이 사라지고 장소가 없어져 버리기 때문입니다
그러므로 이 모달에 간단한 진행 표시줄 하나를 추가하겠습니다
이 표시줄은 남은 시간에 따라 줄어들면서
이는 유저들에게 타이머가 설정되어 있다는 것과
타이머가 만료된다면 장소가 삭제될 예정이라고 알려줄 것입니다
이 작업을 위해 DeleteConfirmation으로 가서
빌트인 progress 요소를 추가하겠습니다
마지막 마무리 디브(div)의 바로 앞에 추가하겠습니다
진행 표시줄을 보여주기 위해 사용되기도 하고
진행 표시줄의 상태, 즉 차 있는 정도를
제어하는 데에도 사용하겠습니다
그러기 위해선 더 잦은 빈도로 변경되는 상태를
운영할필요가 있습니다
그렇게 하면 JSX 코드와 진행 표시줄을
더 자주 반복적으로 렌더링 할 수 있습니다
그러기 위해서, 새로운 상태를
여기 DeleteConfirmation 컴포넌트에 추가할 것입니다
그리고 이 상태를 remainingTime으로 명명하겠습니다
그리고 업데이트 함수는 setRemainingTime으로 하겠습니다
그리고 초기 상태값은 3000으로 추가하겠습니다
그렇게 하면 초기 시간으로 3000 밀리초를 가지게 됩니다
3000으로 하는 이유는 앞서 정한 시간이 3000이었기 때문이고
반복해서 입력하지 않고 싶거나
여러 군데에 넣어둔 값을
변경하기 위해서
일괄적으로 적용될 수 있는 상수값을 추가하겠습니다
이를 3000의 값을 가진 TIMER로 이름 짓고
각 위치에 사용하겠습니다
이제 이 상태를
매 초마다 여러 번 업데이트 해야만
부드럽게 움직이는 진행 표시줄을 만들어낼 수 있습니다
그러기 위해서 또 다른 함수를 사용하겠습니다
바로 브라우저의 빌트인 함수인 setInterval입니다
이름이 알려 주듯이
setTimeout과 연관되어 있습니다
setTimeout은 단순하게 주어진 시간 후에
만료가 되는 타이머를 설정하는 반면
setInterval은 함수를 정의하여
매 몇 밀리 초마다 실행되도록 합니다
예를 들어, 매 10밀리초로 정한다면
매 초마다 100번을 실행하게 됩니다
그리고 이 자주 실행되는 함수가
바로 남은 시간을 업데이트 하고
타이머로부터 10 밀리초를 빼는
설정을 담는 함수입니다
해당 상태에 보관된 이전의값에 기반하여
업데이트 하기 위해
SetRemainingTime을 불러옵니다
여기서 사용할
함수 형식은
상태 업데이트 함수로 전달해서
여기에서 기존 상태 snapshot (스냅샷)을 얻게 됩니다
이제 새로운 remainingTime은 이전 시간 빼기 10이 됩니다
이제 그걸 가지고 ramainingTime을 사용하여
맨 아래에 이 작업 표시줄을 설정하고 업데이트할 수 있습니다
그걸 위해서, value 속성을 설정하고
remainingTime에 동일하게 설정할 수 있습니다
먼저는 3000밀리초고
다음으론 2990, 2980 등등이 됩니다
브라우저에 의해서 진행 표시줄의 찬 정도 상태가
자동으로 계산되게 하기 위해서
최댓값을 설정해야 합니다
그리고 여기에는 TIMER로 설정합니다
여기 3000의 밀리초가 진행 표시줄 상태의
최댓값이 됩니다
그리고 remiaingTime이 업데이트 될 때마다
이것 또한 업데이트 해야합니다
당연히 이것은 상태 업데이트로
매 초마다 여러 번 수행될 업데이트입니다
이렇게 해서 저장하고 다시 불러와서
장소를 추가하고 모달을 열면
만료되어 가는 타이머가 보입니다
그런데 생각보다 빠르게 만료됐습니다
그 이유는, setInterval을 컴포넌트 함수에
설정할 때
문제가 발생했기 때문입니다
이 섹션에 전에 설명한 내용처럼 무한 루프가
생성되었습니다
그래서 다시 useEffect 훅을 사용해서
Eeffect 함수와 의존성 배열을
정의하겠습니다
그리고 이것을 Effect 함수 안으로 옮겨줍니다
이대로 저장해서
다시 새로고침을 하면
무한 루프가 더 이상 생기지 않습니다
무한 루프가 없는 것을 직접 확인하기 위해
console.log에 INTERVAL을 추가해서
setInterval 코드로 옮겨줍니다
이제 매 10초마다 실행하게 됩니다
다시 불러온 다음 개발자 도구를 보면
일단 아무 것도 보이지 않습니다
모달을 여는 순간 아주 많은 INTERVAL 로그가 보입니다
그리고 타이머가 만료되어 가는 것이 보이고 창이 닫힙니다
그러나 INTERVAL은 계속해서 기록됩니다
그 이유는 당연하게도 이 INTERVAL을 멈추지 않았기 때문입니다
그래서 계속 진행됩니다
이전에 모달이 닫혔을 때 타이머가
계속 진행되지 않도록
타이머를 멈추는 작업을 했었습니다
지금은 INTERVAL에 대해 같은 문제를 맞이했고
다행히도 해결책은 같습니다
cleanup (클린업) 함수를 반환하는 것입니다
이는 리액트에 의해 실행될 것이며
Interval에 상수 또는 변수로서
reference (참조)를 보관해줘야 합니다
다행히 setInterval은 이러한 참조를 반환하고
그리고 클린업 함수에서
clearInterval을 실행할 수 있습니다
이는 브라우저에 내장된 함수입니다
이 interval 참조를 clearInterval로 전달하면
그렇게 하면 INTERVAL이
이 클린업 함수가 실행될 때 종료됩니다
여기 빈 의존성 배열이 있으므로
이 경우는
DeleteConfirmation 컴포넌트가 삭제될 때와 같습니다
즉 DOM으로부터 삭제되는 unmount (언마운트) 상황입니다
이대로 저장하고 새로고침을 하겠습니다
조금 기다렸다가 장소를 추가하고 모달을 열면
INTERVAL도 있고 타이머도 있습니다
로그 메시지가 더 나오지 않는다면 완성입니다
그래서 useEffect를 사용해서
무한 루프를 피함과 동시에
클린업 함수를 사용해서
백그라운드에서 계속해서 진행되는
더 이상 불필요한 처리 과정을 피하는
두 가지 경우에 대해 알아봤습니다