3월부터 본격적으로 시작하게된 next.js 프로젝트가 종료되었다.
리액트의 경험도, 타입스크립트의 경험도 없었지만 3월에 next.js 프로젝트에 들어가게되어
2월동안 급하게 리액트 강의와 타입스크립트 강의 및 디자인 패턴에 관한 공부를하였다,
프로젝트를 진행하면서 바쁜거도 바쁜거지만 퇴근 후 컴포넌트 학습과, 오늘의집을 클론코딩하기로
마음먹고 nest.js를 학습하여 현재도 클론 코딩중에 있다,,,api와 프론트 단 모두 구현하려니 생각보다
더디긴 하지만 그래도 정해진 일정이 있는건 아니니 조금 더 코드에 대하여 고민하면서 학습할수있는게
현재로서는 너무 만족스럽다.
클론코딩을 진행중 회원가입에 타이머 인증을 구현하다가 오늘의집에 타이머가 브라우저에서 다른일을 하면,
시간이 제대로 동작하지않는 문제점을 발견했다.
찾아본 결과 타이머는 정확하지 않으며, 1초마다 실행되길 원했지만 실제로는 그보다 훨씬 긴 간격으로 실행되며, 1초라고 지시한건 “1초마다 실행해”라는 뜻이 아니고, “1초동안은 실행하지 마“라는 뜻이다.
실제로 실행되는 주기는 1.8초일수도 있고 2.5초일수도,,그러니 여러번 반복하면 3분이 아니고 6분일지 9분일지 알 수 없다는걸 알게되었다.
import { useEffect, useLayoutEffect, useRef } from 'react';
const useInterval = (callback: () => void, delay: number | null) => {
const savedCallback = useRef(callback);
useLayoutEffect(() => {
savedCallback.current = callback;
}, [callback]);
useEffect(() => {
if (!delay && delay !== 0) return;
const id = setInterval(() => savedCallback.current(), delay);
return () => clearInterval(id);
}, [delay]);
};
export default useInterval;
useInterval 같은 경우에는 검색해보면 많은 내용이 나와있다.
요약 하자면,
하지만 내가 의도한건 시간보장이 된다고 생각했지만, 여전히 여러가지 테스트를 거쳤을때 완벽하게
시간이 보장되지 않았다, 그래서 requesAnimationFrame을 이용하면 어떨까 생각해보았다.
import { useEffect, useRef } from 'react';
const useRequestTimer = (callback: (deltaTime: number) => void) => {
const requestRef = useRef<number | null>(null);
const previousTimeRef = useRef<number | undefined>();
const animate = (time: number) => {
if (previousTimeRef.current != undefined) {
const deltaTime = time - previousTimeRef.current;
callback(deltaTime);
}
previousTimeRef.current = time;
requestRef.current = requestAnimationFrame(animate);
};
useEffect(() => {
requestRef.current = requestAnimationFrame(animate);
return () => {
if (requestRef.current) {
cancelAnimationFrame(requestRef.current);
}
};
}, []);
};
export default useRequestTimer;
요약 설명
2개의 가장 큰 차이점은 useRequestTimer 훅은 requestAnimationFrame을 사용하여 애니메이션 프레임마다 호출되는 방식으로 타이머를 구현하고 useInterval 훅은 setInterval을 사용하여 주어진 시간 간격마다 호출되는 방식으로 타이머를 구현한다.
즉 , requestAnimationFrame은 브라우저의 리플로우와 리페인트 주기에 맞춰 호출되므로, 브라우저의 최적화된 프레임 주기(초당 60프레임)에 따라 작업이 실행되고 setInterval은 브라우저의 일반적인 타이머 메커니즘에 의존한다.
codesandbox를 통하여 useRequestTimer를 사용한 타이머와 useInterval을 사용한 타이머를 비교해보았을때 useRequestTimer가 더 정확한 타이머를 구현하는거 처럼 보였다. 하지만 requestAnimation은
디스플레이 장치의 주사율을 따라가며, 이는 높은 주사율을 가진 컴퓨터에서는 더 정확한 타이머를 구현할 수 있으며, 주사율이 낮을수록 정확성이 떨어질 수 있다는 문제점이 있다. 다른 성능의 컴퓨터에서 테스트를 하지는 못하여 실제로 어떻게 다르게 작동할지는 직접 눈으로 확인하지는 못햇다.
결론은 2개 다 내가 만족할만한 결과를 이루지는 못했다. 다음 대안은 date객체의 getTime()메서드를 이용해야 비교적 정확한 카운트가 가능하다니 useInterval과 조합하여 새로운 hooks을 만들고 테스트 해볼 예정이다.