useRef는 리액트의 최적화를 위하여 사용될 수 있다.
1)값을 참조하거나
2)랜더링과 상관없는 Dom을 조작하려고 할때
3)ref 컨텐츠를 여러번 재창조하여야 하는 것을 피하기 위해 사용된다.
아래와 같은 예시는 흐른 시간을 표시하는 코드인데 start 버튼을 누르면
now =Date.time()이 실행되고 now-start 시간이 계산되어 흐른 시간이 표시되는
코드인데 setInterval로 생성된 인터벌을 컴포넌트의 상태나 변수에 직업 저장하면
해당 상태가 업데이트 될 때마다 새로운 인터벌이 생성되면서
불필요한 리소스 사용과 메모리 누수로 이어질 수 있다.
따라서 setInterval을 useRef에 담아서 참조하게 해주었다.
그 전에 흐른 시간 계산기 만드는 법을 까먹어서 JS로 만드는 것을 다시 해보았다.
let start;
let now;
let intervalId;
function calculateTime() {
now = Date.now();
const elaps = (now - start) / 1000;
const min = Math.floor(elaps / 60);
const sec = Math.floor(elaps % 60);
const formattedTime = `${String(min).padStart(2, "0")}:${String(sec).padStart(
2,
"0"
)}`;
document.getElementById("time").textContent = formattedTime;
}
const erase = () => {
clearInterval(intervalId);
console.log("스탑버튼이 눌렸다. ");
};
//버튼을 클릭하면 start time을 시작해야 한다.
const handleStart = document.getElementById("start");
handleStart.addEventListener("click", function () {
start = Date.now();
//1초에 한번씩 초를 바꿔준다.
intervalId = setInterval(calculateTime, 1000);
});
const handleStop = document.getElementById("stop");
handleStop.addEventListener("click", erase);
그리고 intervalId 을 const intervalRef = useRef(null); 로 바꾸어준다.
import { useState, useRef } from 'react';
export default function Stopwatch() {
const [startTime, setStartTime] = useState(null);
const [now, setNow] = useState(null);
const intervalRef = useRef(null);
function handleStart() {
setStartTime(Date.now());
setNow(Date.now());
clearInterval(intervalRef.current);
intervalRef.current = setInterval(() => {
setNow(Date.now());
}, 10);
}
function handleStop() {
clearInterval(intervalRef.current);
}
let secondsPassed = 0;
if (startTime != null && now != null) {
secondsPassed = (now - startTime) / 1000;
}
return (
<>
<h1>Time passed: {secondsPassed.toFixed(3)}</h1>
<button onClick={handleStart}>
Start
</button>
<button onClick={handleStop}>
Stop
</button>
</>
);
}