
현재 작업중인 포모도로 공부법 사이드 프로젝트를 만들고 있는데, 이전부터 해보고 싶었던 svg로 원을 그리고 여기에 타이머 애니메이션 이펙트를 주는 것을 작업하고 있다.
<svg height="100%" width="100%"> // 뷰박스 대신 컨테이너 전체의 크기를 받는다.
<circle
cx="50%"
cy="50%" // cx cy를 50%씩 주게 되면 해당 컨테이너의 중앙에 위치하게 된다.
r="48%" // 원의 지름을 결정한다. 지름 선의 굵기에 따라 조절.
strokeLinecap="round" // 선의 끝선 스타일
strokeDasharray={ // 해당 shape, 이 경우에는 원을 점선으로 표현한다는 선언. 퍼센트로 사용할 경우에는,
// 현 뷰포트(위의 값이 따라 컨테이너의 전체 크기)에 따라 계산된다. (2 *pi) * r 의 계산식이므로 위의 r값으로 계산하면 300퍼(대략)이 된다.
getIsStarted === "stopped" && isOriginalTime ? 0 : "300%" // 0이면 점선을 사용하지 않기 떄문에, 그냥 원 형태가 된다. 타이머가 돌아가는 도중에는 애니메이션 구현을 위해 완전한 원형으로 점선을 표현해 준다.
}
strokeDashoffset={
// 위 dashArray와 같은 값으로 시작해서, 점점 줄어들게 된다.
getIsStarted === "stopped" && isOriginalTime
? `0%`
: `${circleOffset}%`
}
/>
</svg>
const Clock = () => {
const {
isStarted: { get: getIsStarted, set: setIsStarted },
tab: { get: getTab, set: setTab },
} = usePomodoro(["isStarted", "tab"]);
const [circleOffset, setCircleOffset] = useState(300);
const tick = () => {
setTab({ ...getTab, countdown: (getTab.countdown as number) - 1000 });
setCircleOffset((prev) => prev - 1);
};
const { getTime } = useClock(tick);
const time = getTime();
const isOriginalTime = findTab(getTab.title).countdown === getTab.countdown;
return (
크게 생각할 것 없이, 인터벌 주기에 맞게 오프셋을 1씩 깎아서 svg가 조금씩 그려지도록 잡아준다.

그렇다. 1초마다 시간을 계산하고 offset값을 깎아주기 때문에, 스무스한 효과가 나오지 않는다.
애초에 타이머 값과 offset이 달라지는 지점및 밸류가 아예 다르다면 문제가 없겠지만, 아무래도 한곳에서 모두 처리를 하고 싶으니깐...
간단하게 생각해본다면 실제 시간이 1초 줄어들 때 offset 값은 1번 이상(대략적으로 10번정도)가 줄어들면 될 수 있겠다. setState의 빈도수가 확 늘어날 것이기 때문에.. 아니라면 아예 setTimeout이 아닌 다른 방법을 찾을 수도 있지 않을까 한다.