이제 제법 고급진 방법으로
이 ResultModal을
TimerChallenge 내에서 띄우는 법을 배웠습니다
이제는
이 TimerChallenge 컴포넌트를 조금 더 업그레이드해볼 시간입니다
제 목표는 여기서 '졌습니다'라고 말하는 것 뿐 아니라
이 모달을 띄우는 것이기 때문입니다
타이머를 성공적으로 멈췄을 때 그렇게 할 것이고
그리고 점수를 그 창에 보여줄 것입니다
그러기 위해서
그저 타이머를 설정하고 멈추는 기능은 충분하지 않습니다
대신, 이제는 시간이 얼마나 남았는지 측정해야 합니다
지속적으로 말입니다
그래야 타이머가 멈춰졌을 때
시간이 얼마 남았는지 알 수 있습니다
setTimeout은 그런 정보를 주지 않습니다
그러므로 setInterval (간격설정) 이 필요합니다
이건 자바스크립트의 또 다른 내장 함수입니다
정확하게는 브라우저의 내장 기능입니다
이제 setInterval은 setTimeout과 다르게 작동합니다
왜냐하면 setInterval은 여기 이 함수를
이 시간이 만료될 때마다 실행할 것이며, 한 번만이 아닙니다
그러므로 여기서 물론
targetTime을 시간으로 설정하지 않고
아주 짧은 기간으로 설정합니다
그래야 얼마나 시간이 만료됐는지 추적할 수 있습니다
예를 들어, 이 함수를
밀리초마다 실행할 수 있습니다
하지만 그건 너무 많이 실행이 될 것이고
성능에 좋지 않은 영향을 끼칠 것입니다
그래서 10 밀리초로 해보겠습니다
하지만 이 값은 여러분이 다양하게 시도해보셔도 됩니다
그리고 여기, 더 이상 이 타이머가 만료되었다고
표시하고 싶지 않습니다
대신, 완전히 바꿔야 합니다
여기서 제어하는 이 상태들 말입니다
그리고 남은 시간을 추적하는 것은
상태를 통해 해야 합니다
그러니 이 상태 값들을 지우고
새로운 상태를 등록합니다
남은 시간을 다루는 거니까
timeRemaining (남은 시간)으로 하겠습니다
그리고 그에 맞는 업데이트 함수도 물론 추가합니다
이제 초기에는 그게 targetTime이어야 합니다
이런 식으로 말입니다
targetTIme은 밀리초 단위이길 원합니다
왜냐하면 이 간격이 10 밀리초이기 때문입니다
그리고 이 남은 시간을
10 밀리초마다 업데이트하고 싶습니다
그러니 초기 시간을 밀리초로 설정하겠습니다
즉, targetTime 곱하기 1000입니다
그리고 이 함수는
10 밀리초마다 실행되는 것인데
남은 시간을 업데이트할 때
setTimeRemaining을 호출해야 합니다
그리고 현재 남은 시간으로부터 10 밀리초를 빼야 합니다
그러니까 배웠듯이
이 함수 형식을 써야 합니다
자동으로 이전 timeRemaining을 받고
그리고 새 값을 반환해서
상태로 설정합니다
그리고 이게 이전 남은 시간 - 10입니다
그래서 여기서 10 밀리초를 빼줘야 합니다
그러니 결국 이 상태는
업데이트된 timeRemaining으로 10 밀리초마다 업데이트되는 것입니다
이 setTimerStarted는 제거해줍니다
왜냐하면 이제는 이렇게 설정합니다
예를 들어 타이머가 활성화되는 조건이
timeRemaining이 0보다 크고
targetTime 곱하기 1000보다 작을 때라고 해봅시다
왜냐하면 그것보다 작으면, 타이머가 시작된 걸 알 수 있기 때문입니다
그렇지 않으면 일치할 것입니다
그게 초기 timeRemaining일 것이기 때문입니다
그리고 만약 0보다 작다면
타이머가 활성화되면 안 됩니다
만료되어 targetTime이 다 되었다는 뜻이니까 말입니다
이제 물론 이 간격은
handleStop이 실행되어도 멈춰져야 합니다
즉, 이 '중지' 버튼이 눌려도 말입니다
하지만 이 간격을 clearTimeout으로 지울 수 없습니다
대신 clearInterval을 사용해야 하며
브라우저에 내장된 기능입니다
그리고 setTimeout 함수와 마찬가지로
setInterval 또한 참조를 반환합니다
그걸 이 ref에 저장해줍니다
그러면 사용할 수 있습니다
그리고 여기서도 변수가 아닌 참조를 사용해야 합니다
상태도 안 됩니다, 이유는 전과 같습니다
그러면 이제 이 타이머를 멈출 수 있지만
이게 만료되었어도 수동으로
멈추고 싶습니다
'중지' 버튼이 눌렸을 때 뿐만 아니라 말입니다
그러므로 이 컴포넌트 함수에서
if문을 추가합니다
그리고 timeRemaining이 0보다 작거나 같은지 확인합니다
왜냐하면 0보다 작거나 같으면
시간이 다 됐고 남은 시간이 없다는 것을 알 수 있습니다
하지만 setInterval은 스스로 멈추지 않습니다
마감 기간이 정해져 있지 않기 때문입니다
그저 10 밀리초마다 재실행됩니다
그래서 이 interval (간격) 또한
시간이 다 되면 없애야 합니다
그건 timeRemaining이 0보다 작거나
같을 때의 경우입니다
그래서 여기, clearInterval과 그 안에
timer.current를 호출합니다
우리가 여기 설정한 interval (간격)입니다
그래야 이 간격이 계속 실행되지 않습니다
추가로 이 if문에서
setTimeRemaining도
초기 targetTime 곱하기 1000으로 도로 설정해줍니다
상태를 이런 식으로
컴포넌트 함수 내에서 바로 설정하는 것은 위험할 수도 있습니다
무한 루프가 생성될 수 있기 때문입니다
상태를 설정하는 건 컴포넌트 함수를
다시 실행하게 하기 때문입니다
그래서 이 함수를 계속 재실행하게 할지도 모릅니다
하지만 여기선 if 조건에 있기 때문에
이런 식으로 상태를 업데이트하지 않는 이상 다다르지 않을 것이고
무한 루프가 생성되지는 않을 것입니다
하지만 이런 위험성을 염두에 두는 것이 좋습니다
이런 식으로 상태 업데이트 함수를
컴포넌트에서 바로 호출할 때 말입니다
이런 식으로 말입니다
하지만 이런 조건이라면, 사용해도 괜찮습니다
그러면 이제 , JSX 코드를 조정해야 합니다
그리고 이 밑에, 예를 들어
이 버튼이
handleStop 함수를 실행시키도록 하고 싶습니다
timerIsActive여야 하고 그게 아니면 handleStart입니다
여기서도 timerIsActive를 사용하고 싶습니다
여기서도, 여기서도 사용합니다
그래야 새로 파생된 상태를 사용합니다
이 새로 계산된 값으로
UI를 제대로 업데이트할 수 있습니다
그러면 그걸로
물론 우리가 해야 하는 것은
이 모달을 띄우는 것입니다
그리고 그건 handleStop이나 타이머가 만료되었을 땐
일어나면 안되는 일입니다
그래서 여기에 만약 타이머가 만료되면
dialog 참조를 사용합니다
그건 결국
resultModal 컴포넌트를 참조하는 것입니다
그 다음에 .current.open을 호출해줍니다
그리고 handleStop 안에서 똑같이 해줍니다
차이점은 여기서
타이머를 수동으로 멈춘다는 것입니다, 이겼다는 뜻이죠
그리고 여기서는 타이머가 만료되었습니다
왜냐하면 시간 내에 멈추지 못했고, 졌다는 뜻입니다
하지만 여기서 호출하는 함수, 즉 open 함수는
항상 같습니다
그러면 저장을 해보겠습니다
시작하고 그대로 두겠습니다
이 창이여전히 열리고 '졌습니다'가 보입니다
만약에 멈춰보면, 그래도 열립니다
그리고 문구가 똑같은데 아직 업데이트하지 않아서 그렇습니다
하지만 이제 모달 창이 두 경우 다 열리는 것을 확인했습니다
진짜 패배한 경우와 시간 내 잘 멈춘 경우 둘 다 말입니다
이제부터 할 일은
모달에 정확한 정보가 전달되는 것입니다