2020. 7. 27. 18:30ㆍ웹돌이 단편선
2020/07/23 - [웹돌이 단편선] - [웹으로 낙서하기#1]자바스크립트를 사용해서 웹 브라우저에 디지털 시계를 올려놔보자!
[웹으로 낙서하기#1]자바스크립트를 사용해서 웹 브라우저에 디지털 시계를 올려놔보자!
웹으로 낙서하기 시리즈를 여는 글로써, 자바스크립트를 사용해 디지털 시계를 만들어보겠습니다. 필요한 기능 현재 시간을 HH:mm:ss 포맷으로 보여준다. 디지털 시계다. 1초마다 초가 흐른다. 필�
exilee20c.tistory.com
이전 글에서는 디지털 시계 외형을 만들어봤다. 이번 글에서는 시계답게 1초마다 시간이 흐르는 것을 보여주는 간단한 코딩을 하겠다.
이전 글의 DigitalClock 컴포넌트로부터 시작한다.
시계는 그 자체로 시간의 흐름을 갖고 있기 때문에 스스로 state를 갖고 있다.
import React, { useState } from "react";
import Digit from "../../atoms/Digit";
function getZeroPadString(number) {
return number.toString().replace(/([0-9])?([0-9])$/g, function (_, $1, $2) {
return `${$1 || 0}${$2}`;
});
}
function mapDigit(digit, i) {
return <Digit key={i} value={digit} />;
}
function DigitalClock() {
const [date, setDate] = useState(new Date());
const HH = getZeroPadString(date.getHours());
const mm = getZeroPadString(date.getMinutes());
const ss = getZeroPadString(date.getSeconds());
return (
<div>
{Array.from(HH).map(mapDigit)}:{Array.from(mm).map(mapDigit)}:
{Array.from(ss).map(mapDigit)}
</div>
);
}
export default DigitalClock;
마운트시 1초마다 시간을 갱신하는 훅을 추가해 보겠다.
function DigitalClock() {
const [date, setDate] = useState(new Date());
const refreshDate = useRef(() => setDate(new Date()));
useEffect(() => {
const interval = setInterval(refreshDate.current, 1000);
return () => clearInterval(interval);
}, []);
const HH = getZeroPadString(date.getHours());
const mm = getZeroPadString(date.getMinutes());
const ss = getZeroPadString(date.getSeconds());
return (
<div>
{Array.from(HH).map(mapDigit)}:{Array.from(mm).map(mapDigit)}:
{Array.from(ss).map(mapDigit)}
</div>
);
}
이때 밀리초 단위까지 시간을 보여주면 꽤나 불편한 상황을 볼수 있다.
그래서 초기 렌더링시 520밀리초가 흐른 상태라면 1000밀리초로 setInterval 하는것이 아닌, 1000밀리초 - 520밀리초 = 480밀리초 후에 타임 아웃을 걸고, 매 틱마다 1000 밀리초 - x밀리초만큼의 다음번 타임아웃을 재귀적으로 설정해봤다.
import React, { useState, useRef, useEffect } from "react";
import Digit from "../../atoms/Digit";
function getZeroPadString(number, stack = 1) {
const remainStack = stack - 1;
const fn =
remainStack > 0 ? (i) => getZeroPadString(i, remainStack) : (i) => i;
return number.toString().replace(/([0-9]*)?([0-9])$/g, function (_, $1, $2) {
return `${fn($1 || 0)}${$2}`;
});
}
function mapDigit(digit, i) {
return <Digit key={i} value={+digit} />;
}
function DigitalClock() {
const [date, setDate] = useState(new Date());
const dateRef = useRef(date);
const refreshDate = useRef(() => {
const newDate = new Date();
setDate(newDate);
dateRef.current = newDate;
nextTick.current();
});
const nextTick = useRef(() =>
setTimeout(refreshDate.current, 1000 - dateRef.current.getMilliseconds())
);
useEffect(() => {
const timeout = nextTick.current();
return () => clearTimeout(timeout);
}, []);
const HH = getZeroPadString(date.getHours());
const mm = getZeroPadString(date.getMinutes());
const ss = getZeroPadString(date.getSeconds());
const SSS = getZeroPadString(date.getMilliseconds(), 2);
return (
<div>
{Array.from(HH).map(mapDigit)}:{Array.from(mm).map(mapDigit)}:
{Array.from(ss).map(mapDigit)}:{Array.from(SSS).map(mapDigit)}
</div>
);
}
export default DigitalClock;
코드는 위와 같았고, 다음과 같은 결과가 보여졌다.
이 이상 좁힐수 없는 오차는 다음번 틱을 재귀적으로 호출하기 위한 연산 시간만큼의 지연시간 때문일 것인데, 이 시간도 줄일수 있는 방법은 추후에 고민을 해봐야겠다. 당장은 오차가 크지 않고, 초단위까지만 보여줘도 충분하기 때문에 시분초까지만 출력을 하며 마치겠다.
import React, { useState, useRef, useEffect } from "react";
import Digit from "../../atoms/Digit";
function getZeroPadString(number, stack = 1) {
const remainStack = stack - 1;
const fn =
remainStack > 0 ? (i) => getZeroPadString(i, remainStack) : (i) => i;
return number.toString().replace(/([0-9]*)?([0-9])$/g, function (_, $1, $2) {
return `${fn($1 || 0)}${$2}`;
});
}
function mapDigit(digit, i) {
return <Digit key={i} value={+digit} />;
}
function DigitalClock() {
const [date, setDate] = useState(new Date());
const dateRef = useRef(date);
const refreshDate = useRef(() => {
const newDate = new Date();
setDate(newDate);
dateRef.current = newDate;
nextTick.current();
});
const nextTick = useRef(() =>
setTimeout(refreshDate.current, 1000 - dateRef.current.getMilliseconds())
);
useEffect(() => {
const timeout = nextTick.current();
return () => clearTimeout(timeout);
}, []);
const HH = getZeroPadString(date.getHours());
const mm = getZeroPadString(date.getMinutes());
const ss = getZeroPadString(date.getSeconds());
return (
<div>
{Array.from(HH).map(mapDigit)}:{Array.from(mm).map(mapDigit)}:
{Array.from(ss).map(mapDigit)}
</div>
);
}
export default DigitalClock;
'웹돌이 단편선' 카테고리의 다른 글
[웹으로 낙서하기#3]자바스크립트로 스탑워치를 만들어보자! (6) | 2020.07.30 |
---|---|
[웹으로 낙서하기#1]자바스크립트를 사용해서 웹 브라우저에 디지털 시계를 올려놔보자! (0) | 2020.07.23 |
VSCode로 리액트 개발할 때 쓰기 편한 스니펫 모음 (1) | 2020.07.18 |