문제사항
Hook에서 setInterval()
을 사용하면?
- Function Component에서 Hook을 이용하여 state 관리를 진행한다.
이때 Vanila Javascript처럼 setInerval()
을 받는 함수를 설정하고 특정 조건이 되면 해제하는 형식은 원하는 대로 동작이 이루어지지 않는다.
const [value,setVale] = useState(1);
const [isIncrease,setIsIncrease] = useState(false);
useEffect(()=>{
function tick(){
return setInterval(()=>setValue(value+1),1000);
}
return isIncrease ? tick() : ()=>{clearInterval(tick)};
},[value,isIncrease])
- 위와 같이 작성하면, 계속해서
value
값은 버벅일 것이다. setValue()
가 끊임없이 발생해서, 원하는대로 setInterval()
이 작동하지 않는다.
- 기본적으로 React 프로그래밍 모델은
setInterval()
과 부조화가 발생해서 일어나는 일이기도 하다.
해결방법
setTimeout
을 이용하자!
- 기본적으로 반복적으로 계속해서 콜백함수를 호출하는
setInterval()
대신 setTimeout()
을 사용하는 것은 현명한 선택이 될 수 있다.
- 위의 코드를 그럼 다음과 같이 바꾸면 된다.
const [value,setVale] = useState(1);
const [isIncrease,setIsIncrease] = useState(false);
useEffect(()=>{
function tick(){
return setTimeOut(()=>setValue(value+1),1000);
}
return isIncrease ? tick() : ()=>{clearInterval(tick)};
},[value,isIncrease])
- 그렇지만 여전히 정상적으로 작동하지는 않는다.
isIncrease
가 true
라 할지라도 tick()
에 부여된 Interval
를 tick()이 동작한 이후에 없애줘야 하기때문이다.
hook의 return 값으로 clearTimeout()
을 설정하자!
- 위의 상황을 해결하기 위해선
setTimeout()
이 작동하는 useEffect
마다 clearTimeout()
을 작동시키는 코드를 return 값으로 넣는 것이다.
const [value,setVale] = useState(1);
const [isIncrease,setIsIncrease] = useState(false);
useEffect(()=>{
function tick(){
return setTimeOut(()=>setValue(value+1),1000);
}
if(!isIncrease) return undefined;
tick();
return ()=>clearTimeOut(tick);
},[value,isIncrease])
- Early return 까지 적용되어 훨씬 깔끔한 코드가 되었다.
setTimeOut
과 관련된 value만 따로 처리하자!
useEffect(() => {
if (gameProcessData.isGameStart) {
const tick = setInterval(() => {
setGameData({
...gameData,
time: gameData.time + 1,
});
}, 1000);
return () => clearInterval(tick);
}
return undefined;
}, [gameData, gameProcessData]);
gameData
안에서 계속해서 time
을 증가시켰는데, 이경우에 gameData
의 다른 부분이 변경되도 time을 증가시키는 코드를 동작시키는 것이 문제였다.
- 따라서 아래와 같이
time
변수를 분리해서 새로운 state
로 만들었고 이 부분을 해결했다.
const [time, setTime] : [number, Function] = useState(0);
useEffect(() => {
if (!gameProcessData.isGameStart) return undefined;
const tick = setTimeout(() => {
setTime(time + 1);
}, 1000);
return () => clearTimeout(tick);
}, [time, gameProcessData]);
참고사이트
function tick(){
return setTimeOut(()=>setValue(value+1),1000);
}
if(!isIncrease) return undefined;
tick();
return ()=>clearTimeOut(tick);
tick() 호출시 setTimeout 객체가 생성되며 리턴되는데 리턴값을 저장하지않고
clearTimeOut에서 인자로 함수를 지정하는데 js 몇에서 유효한 코드인가요 ??