React - Timer 분/초/소수점 타이머 만들기

반응형

Next.js 에서 React와 TypeScript를 이용해서 타이머를 구현해보도록 하겠습니다.

 

React Hook은 useEffect와 useMemo를 사용하였습니다.

 

1. 컴포넌트 렌더링 시 setInterval 함수를 통해서 1초 감소

2. setInterval 종료

3. 다시 재렌더링

 

이런 메커니즘으로 타이머가 진행 됩니다.

 

1분 이하에는 0.1초 단위로 시간이 내려갑니다.

See the Pen React + TypeScript Starter by powerku (@powerku) on CodePen.

타이머 컴포넌트

timer.tsx

const Timer = ({minute = 15, second = 0}: TimerProps) => {
    const [min, setMinute] = React.useState(1)
    const [sec, setSecond] = React.useState(2)
    const [milliSec, setMilliSec] = React.useState(0)
    const [isRunning, setIsRunning] = React.useState(false);
    const [minuteSecondMode, setIsMinuteSecondMode] = React.useState(true);

    const formatMinute = React.useMemo(() => {
        return min.toString().padStart(2, '0')
    }, [min])

    const formatSecond = React.useMemo(() => {
        return sec.toString().padStart(2, '0')
    }, [sec])

    React.useEffect(() => {
        if (min === 0) {
            setIsMinuteSecondMode(false);
        }
    }, [min]);

    React.useEffect(() => {
        if (!isRunning) {
            return;
        }

        let interval;

        if (minuteSecondMode) {
            interval = setInterval(() => {
                if (sec > 0 ) {
                    setSecond(sec - 1)
                } else if (sec === 0 && min > 0) {
                    setMinute(min - 1)
                    if (min !== 0) {
                        setSecond(59)
                    }
                }
            }, 1000)
        } else {
            interval = setInterval(() => {
                if (milliSec > 0 ) {
                    setMilliSec(milliSec - 1)
                } else if (milliSec === 0 && sec > 0) {
                    setSecond(sec - 1)
                    if (sec !== 0) {
                        setMilliSec(9)
                    }
                }
            }, 100)
        }

        return () => clearInterval(interval)
    });

    const go = () => {
        setIsRunning(isRunning => !isRunning);
    }

    const reset = () => {
        setMinute(minute);
        setSecond(second);
        setMilliSec(0)
        setIsRunning(false);
        setIsMinuteSecondMode(true);
    }

    return (
        <>
            {minuteSecondMode ? <>
                <span>{formatMinute}:</span>
                <span>{formatSecond}</span>
            </>: <>
                <span>{formatSecond}.</span>
                <span>{milliSec}</span>
            </>
            }
            <div>
                <button onClick={go}>{isRunning ? 'Stop':'Start'}</button>
                <button onClick={reset}>Reset</button>
            </div>
        </>
    );
};
728x90
반응형