Front-end/React
useInterval 커스텀 훅
NiceKHJ
2025. 11. 27. 17:44
useInterval 커스텀 훅 사용 이유
문제점 :
- React에서 setInterval을 그냥 쓰면 클로저 문제 발생 한다
state가 업데이트되어도 interval 안에서는 옛날 값을 참조하기 때문에 - 메모리 누수 발생할 수 있다.
cleanup을 제대로 안 하면 컴포넌트가 unmount 되어도 interval이 계속 실행되기 때문에 - 코드 복잡도가 증가함
useEffect 안에서 setInterval과 clearInterval을 매번 작성해야하기 때문에
useInterval의 장점 :
- state 최신값을 항상 참조
- 자동 cleanup으로 메모리 누수 방지
- delay를 null로 바꾸면 일시정지 가능
- 재사용 가능한 깔끔한 코드
일반 setInterval의 문제점 (예시)
function Counter() {
const [count, setCount] = useState(0);
useEffect(()=>{
const id = setInterval(()=>{
console.log(count); // 항상 0만 출력
setCount(count + 1) //count가 업데이트 안됨
},1000)
return ()=> clearInterval(id)
},[]) //빈 배열이면 처음 count 값만 기억함
return <div>{count}</div>
}
- useEffect의 의존성 배열이 [ ] 이면 처음 렌더링 때의 count 값만 기억
- interval 내부는 계속 count = 0 을 참조
useInterval 커스텀 훅 코드
import { useEffect, useRef } from "react";
export default function useInterval(callback, delay) {
const savedCallback = useRef();
//callback이 바뀔 때마다 ref에 저장함
useEffect(()=>{
savedCallback.current = callback;
},[callback])
// delay가 바뀔때마다 interval 재설정
useEffect(()=>{
//delay가 null이면 interval 안 돌아감
if(delay === null){
return;
}
function tick() {
savedCallback.current();
}
const id = setInterval(tick, delay);
// cleanup : interval 정리
return () => clearInterval(id);
},[delay])
}
- useRef로 최신 callback을 저장 - 클로저 문제 해결
- 첫번째 useEffect는 callback이 바뀔때마다 ref 업데이트
- 두번째 useEffect는 delay가 바뀔때만 interval 재설정
- return () => clearInterval(id) 로 자동 cleanup
사용 예시 (카운트)
import { useState } from 'react';
import useInterval from './useInterval';
function Counter() {
const [count, setCount] = useState(0);
const [timeGo, setTimeGo] = useState(true);
useInterval(()=>{
setCount(prev => prev + 1);
}, timeGo ? 1000 : null); // null이면 멈춘다
return(
<div>
<h1>{count}</h1>
<button onClick={() => setTimeGo(!timeGo)}>
{timeGo ? '정지' : '시작'}
</button>
</div>
)
}