Skip to main content

리액트에서 몇 초 간격으로 Polling 하는 로직을 만들 때 유의할 점(Feat. 타이머)

Bad Case

  • setInterval 콜백에서 setCount(count + 1)을 호출할 때, count 변수는 useState 훅에서 설정한 초기 값을 참조합니다.

이는 useEffect 콜백함수가 컴포넌트 마운트 시 한 번만 호출되기 때문에

count의 초기 값이 클로저에 의해 캡쳐됩니다.

import React, { useEffect, useState } from "react";

const App = () => {
const [count, setCount] = useState<number>(0);

useEffect(() => {
let i = 0;
const interval = setInterval(() => {
console.log("i: ", i++);

// 이렇게 할 경우, count의 이전 값인 0을 계속 사용하기 때문에// setCount를 아무리 해줘도 업데이트 된 count는 항상 1
setCount(count + 1);
}, 1000);

return () => clearInterval(interval);
}, []);

return <div>{count}</div>;
};

export default App;

Good Case

이를 함수형 업데이트를 이용해서 setCount를 해서 최신 상태값을 업데이트 하는 것이 좋습니다.

함수형 업데이트는 상태의 최신 값을 보장합니다.

useState 훅의 setter 함수는 비동기적으로 업데이트 하므로,

이전 상태 값을 가져오는 것이 좋습니다.

setCount((prev) => prev + 1)에서 이전 상태값은 prev입니다.

더 자세히 말하면 클로저를 이용해 상태값을 사용합니다.

import React, { useEffect, useState } from "react";

const App = () => {
const [count, setCount] = useState<number>(0);

useEffect(() => {
let i = 0;
const interval = setInterval(() => {
console.log("i: ", i++);
// 함수형 업데이트를 사용
setCount((prev) => prev + 1);
}, 1000);

return () => clearInterval(interval);
}, [count]);

return <div>{count}</div>;
};

export default App;

리액트의 useState는 비동기적으로 업데이트 됩니다.

다른말로 하면, 같은 state를 동시에 여러번 업데이트 할 경우,

마지막의 setState만 실행되게 합니다.

배치 방식으로 업데이트한다고도 합니다.