
์ฝ๋ ๋ฆฌ๋ทฐ๋ฅผ ์งํํ๋ ์ค, ๊ธฐ์กด ๊ตฌํ๋ ํ์ด๋จธ์์ ์ธํฐ๋ฒ ์์ ์ด ์ง์ฐ๋๋ ๋ฌธ์ ๊ฐ ์๋ค๋ ํผ๋๋ฐฑ์ ๋ฐ์์ต๋๋ค.
๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ ์๊ฐํด๋ณด์์ต๋๋ค.
์๋ ์ฝ๋๋ ์์๋ฅผ ์ํด ์์ฑ๋ ์ฝ๋์ ๋๋ค.
AS-IS. ์๊ฐ์ ์ง์ ๊ณ์ฐ, setInterval๋ก 1์ด๋ง๋ค ๊ฐฑ์
'use client';
import { useEffect, useState } from 'react';
import { atomWithStorage } from 'jotai/utils';
import { useAtom } from 'jotai';
const startTimeAtom = atomWithStorage<number>('inboundProcessStartTime', Date.now());
export default function Timer() {
const [startTime, setStartTime] = useAtom(startTimeAtom);
const [elapsedTime, setElapsedTime] = useState(() => Math.floor((Date.now() - startTime) / 1000));
useEffect(() => {
const updateTimer = () => {
setElapsedTime(Math.floor((Date.now() - startTime) / 1000));
};
updateTimer(); // ์ต์ด ์คํ
const intervalId = setInterval(updateTimer, 1000);
return () => clearInterval(intervalId);
}, [startTime]);
const resetTimer = () => {
const newStartTime = Date.now();
setStartTime(newStartTime);
setElapsedTime(0);
};
const formatTime = (seconds: number) => {
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
const remainingSeconds = seconds % 60;
return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(remainingSeconds).padStart(2, '0')}`;
};
return (
<div>
<p>๊ฒฝ๊ณผ ์๊ฐ: {formatTime(elapsedTime)}</p>
<button onClick={resetTimer}>ํ์ด๋จธ ์ด๊ธฐํ</button>
</div>
);
}
`inboundProcessStartTime` ๋ณ๊ฒฝ ์ ํญ์ ํ์ฌ ์๊ฐ์ ๊ธฐ์ค์ผ๋ก ๊ฒฝ๊ณผ ์๊ฐ์ ๊ณ์ฐํ๋ฏ๋ก, ์ธํฐ๋ฒ ์์/์ทจ์๋ก ์ธํ ์๊ฐ ์ง์ฐ ๋ฌธ์ ๊ฐ ์์ต๋๋ค.- ํ์ฌ ์๊ฐ์ ๊ธฐ์ค์ผ๋ก ์ฐ์ฐ์ ํ์ง๋ง setInterval๋ก ํ๋ฉด ๋ ๋๋ง์ด ๋๋ฉฐ ์๊ฐ ์ง์ฐ ๋ฌธ์ ๊ฐ ๋ฐ์ํฉ๋๋ค.
TO-BE. requestAnimationFrame์ ํตํด ์ ์ฐํ ํ๋ฉด ๊ฐฑ์
setInterval์ ์ฌ์ฉํ๋ ๋์ , requestAnimationFrame์ ํ์ฉํด ๊ฐฑ์ ์ฃผ๊ธฐ๊ฐ ๊ณ ์ ๋ 1์ด๋ณด๋ค ๋ ์ ์ฐํ๊ฒ ๋์ํ์ฌ ์ฆ์ ์๊ฐ์ ์ ๋ฐ์ดํธํ๋๋ก ๊ตฌํํฉ๋๋ค.
"use client";
import { useAtom } from "jotai";
import { atomWithStorage } from "jotai/utils";
import { useEffect, useState } from "react";
const startTimeAtom = atomWithStorage<number>(
"inboundProcessStartTime",
Date.now()
);
export default function Timer() {
const [startTime, setStartTime] = useAtom(startTimeAtom);
const [elapsedTime, setElapsedTime] = useState(() =>
Math.floor((Date.now() - startTime) / 1000)
);
useEffect(() => {
let animationFrameId: number;
const updateTimer = () => {
setElapsedTime(Math.floor((Date.now() - startTime) / 1000));
animationFrameId = requestAnimationFrame(updateTimer);
};
updateTimer();
return () => cancelAnimationFrame(animationFrameId);
}, [startTime]);
const resetTimer = () => {
const newStartTime = Date.now();
setStartTime(newStartTime);
setElapsedTime(0);
};
const formatTime = (seconds: number) => {
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
const remainingSeconds = seconds % 60;
return `${String(hours).padStart(2, "0")}:${String(minutes).padStart(
2,
"0"
)}:${String(remainingSeconds).padStart(2, "0")}`;
};
return (
<div>
<p>๊ฒฝ๊ณผ ์๊ฐ: {formatTime(elapsedTime)}</p>
<button onClick={resetTimer}>ํ์ด๋จธ ์ด๊ธฐํ</button>
</div>
);
}
- inboundProcessStartTime ๋ณ๊ฒฝ ์ฆ์ ํ๋ฉด์ ๋ฐ์๋ฉ๋๋ค.
- requestAnimationFrame ์ ํ์ฉํ์ฌ ๊ฐฑ์ ์ฃผ๊ธฐ๊ฐ ๊ณ ์ ๋ 1์ด๋ณด๋ค ๋ ์ ์ฐํ๊ฒ ๋์ํ๋ฏ๋ก ์ฌ์ฉ์ ๊ฒฝํ์ด ์์ฐ์ค๋ฝ์ต๋๋ค.
- requestAnimationFrame:
- requestAnimationFrame์ ๋ธ๋ผ์ฐ์ ์์ ํ๋ฉด ๊ฐฑ์ ์ฃผ๊ธฐ์ ๋ง์ถฐ์ ์ฝ๋ฐฑํจ์๊ฐ ํธ์ถ๋๋๋ก ์์ฝํฉ๋๋ค. ์ฆ, updateTimer ํจ์๋ ํ๋ฉด์ ๋ค์ ๊ทธ๋ฆด ๋๋ง๋ค ํธ์ถ๋ฉ๋๋ค.
- updateTimer๋ setElapsedTime์ ์ฌ์ฉํด elapsedTime์ ๊ณ์ ๊ฐฑ์ ํ๊ณ , requestAnimationFrame(updateTimer)๋ก ์์ ์ ๋ค์ ํธ์ถํฉ๋๋ค. ์ด๋ก ์ธํด ํ์ด๋จธ๊ฐ ๊ณ์ ๊ฐฑ์ ๋ฉ๋๋ค.
- updateTimer ํจ์๋ requestAnimationFrame์ ํธ์ถํ์ฌ ์์ ์ ๊ณ์ ์คํํ๊ฒ ๋ง๋ญ๋๋ค. ๊ทธ๋์ ํ ๋ฒ updateTimer๊ฐ ์คํ๋๋ฉด, ๊ทธ ๋ค์์๋ ๋ค์ requestAnimationFrame(updateTimer)๊ฐ ํธ์ถ๋๋ฉด์ ๊ณ์ํด์ ์คํ๋ฉ๋๋ค.
- ๋ธ๋ผ์ฐ์ ๊ฐ ํ๋ฉด์ ์๋ก ๊ทธ๋ฆด ๋๋ง๋ค updateTimer๊ฐ ํธ์ถ๋๋ฏ๋ก, ํ์ด๋จธ๋ ํ๋ฉด ๊ฐฑ์ ์ฃผ๊ธฐ๋ง๋ค ์คํ๋ฉ๋๋ค.
- requestAnimationFrame:
Window: requestAnimationFrame() method - Web API | MDN
window.requestAnimationFrame() ๋ฉ์๋๋ ๋ธ๋ผ์ฐ์ ์๊ฒ ์ํํ๊ธฐ๋ฅผ ์ํ๋ ์ ๋๋ฉ์ด์ ์ ์๋ฆฌ๊ณ ๋ค์ ๋ฆฌํ์ธํธ ๋ฐ๋ก ์ ์ ๋ธ๋ผ์ฐ์ ๊ฐ ์ ๋๋ฉ์ด์ ์ ์ ๋ฐ์ดํธํ ์ง์ ๋ ํจ์๋ฅผ ํธ์ถํ๋๋ก ์์ฒญํฉ๋๋ค.
developer.mozilla.org
- references:
์น์์ ์ ํํ ํ์ด๋จธ๋ฅผ ๋ง๋๋ ๋ฐฉ๋ฒ์?
How to make accurate timer in Web
medium.com
Why Javascript timer is unreliable, and how can you fix it
If you are a Javascript developer, at some point in your career, you must have used setTimeout or setInterval. They are extremely handy if…
abhi9bakshi.medium.com
'Front-end' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| useState์ ๋น๋๊ธฐ์ฑ (0) | 2025.04.13 |
|---|---|
| React key prop๊ณผ ์ํ ์ด๊ธฐํ (0) | 2025.02.23 |
| React Server Component๋ฅผ ์ฌ์ฉํด์ผ ํ๋ ์ด์ (0) | 2024.12.15 |
| ์น ํ์ค๊ณผ ์น ์ ๊ทผ์ฑ (0) | 2023.11.29 |
| ๋ชจ๋ ๋ฒ๋ค๋ฌ์ Webpack (1) | 2023.11.23 |