React 공식 문서의 Separating Events from Effects 섹션에서는 useEffectEvent에 대해 설명하고 있습니다. "event와 effect를 분리한다"는 개념이 다소 낯설게 느껴질 수 있는데, 간단한 예시를 통해 자세히 알아보겠습니다.
먼저, useTimeout이라는 hook을 구현해 보겠습니다. 이 hook은 지정된 시간(밀리초) 후에 콜백 함수를 실행해줍니다.
::$SPACE
아래는 기본적인 useTimeout 구현 코드입니다.
const useTimeout = (callback: () => void, delay: number) => {
const timer = useRef<NodeJS.Timeout | null>(null);
const start = useCallback(() => {
timer.current = setTimeout(() => {
callback();
}, delay);
}, [callback, delay]);
useEffect(() => {
return () => {
if (timer.current) clearTimeout(timer.current);
};
}, []);
return useMemo(() => ({ start }), [start]);
};
이제 이 hook을 사용해 보겠습니다.
export const App = () => {
const { start } = useTimeout(() => {
console.log('time out !!');
}, 3000);
return (
<main>
<button onClick={start}>시작</button>
</main>
);
};
시작 버튼을 누르고 3초를 기다리면
time out !! 이 출력됩니다. 이 경우, 코드는 정상적으로 동작합니다.
라고 생각하면 안됩니다.
::$SPACE
어떤 문제가 있을까요? 사용 예제를 다음과 같이 수정해 보겠습니다.
export const App = () => {
const [count, setCount] = useState(0);
const { start } = useTimeout(() => {
console.log(`time out !! 현재 카운트: ${count}`);
}, 3000);
return (
<main>
<button onClick={start}>시작</button>
<button onClick={() => setCount(count + 1)}>증가 (현재: {count})</button>
</main>
);
};
이제 시작 버튼을 클릭한 후, count 증가 버튼을 여러 번 누르면
총 10번 정도 눌렀음에도 불구하고