리액트 에서 setInterval을 작성해 봅시다.
오래전에 구현하느라 애먹었는데 이제야 글을 쓰게 되는군요....
간단하게 코드를 보자면
import { useState } from "react";
import "./styles.css";
export default function App() {
const[cnt, setCnt] = useState(0);
const run = () => {
setInterval(() => {
setCnt(prev => prev + 1);
}, 1000);
}
return (
<div className="App">
<h1>{cnt}</h1>
<button onClick={run}>run</button>
</div>
);
}
버튼을 클릭할 시 count를 1씩 1초마다 증가시킵니다.
잘 작동됩니다.
하지만... 버튼을 계속 클릭하게 되면 숫자 카운트는 빠르게 증가합니다.
대체 왜 그럴까요?
run 버튼을 클릭할 때 마다 기존에 작성했던 setInterval 함수는 clear 되지 않고 그대로 있기 때문입니다.
아직 clear 되지않는 여러개의 sestInterval 함수는 카운트를 1초마다 증가시키지만 여러개가 있으니
이렇게 보이게 되는 것입니다. 한번 다르게 작성해 봅시다.
import { useEffect, useState } from "react";
import "./styles.css";
export default function App() {
const [cnt, setCnt] = useState(0);
let setIntervalID;
useEffect(() => {
return () => clearInterval(setIntervalID);
}, [setIntervalID]);
const run = () => {
if(setIntervalID !== undefined)
return;
setIntervalID = setInterval(() => {
setCnt((prev) => prev + 1);
}, 1000);
};
return (
<div className="App">
<h1>{cnt}</h1>
<button onClick={run}>run</button>
</div>
);
}
컴포넌트가 언마운트 될 때 intervalID를 clear 해줬습니다. 또 버튼클릭 이벤트 발생 시 조건문을 걸어서
리턴해주도록 했습니다.
네 결과는 똑같습니다.
올바르게 작성하기 위해서는 'useRef'를 사용해야 합니다.
import { useEffect, useState, useRef } from "react";
import "./styles.css";
export default function App() {
const [cnt, setCnt] = useState(0);
const timerId = useRef(null);
useEffect(() => {
return () => clearInterval(timerId);
}, [timerId]);
const run = () => {
if (timerId.current !== null) return;
timerId.current = setInterval(() => {
setCnt((prev) => prev + 1);
}, 1000);
};
const stop = () => {
clearInterval(timerId.current);
timerId.current = null;
}
return (
<div className="App">
<h1>{cnt}</h1>
<button onClick={run}>run</button>
<button onClick={stop}>stop</button>
</div>
);
}
useRef는 값이 변한다 하더라도 리액트는 렌더링 하지 않습니다.
useRef의 current 데이터는 컴포넌트라 언마운트 되던 그대로 메모리에 존재하므로
매번 run 버튼을 클릭하더라도 값이 그대로기에 새로운 interval id를 할당하지 않습니다.
'리액트' 카테고리의 다른 글
useEffect 에서 object 타입 dependency 다루기(with:useAxios) (0) | 2022.04.22 |
---|---|
styled-components theme 타입 지정하기 (0) | 2022.04.12 |
Redux는 왜 쓰는 걸까?(1) (0) | 2022.02.21 |
댓글