Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
178 views
in Technique[技术] by (71.8m points)

javascript - Fully functioning countdown timer using React hooks only

Here's my code. You can also check it out on Stackblitz:

import React, { useState } from 'react';

const Timer = ({
    initialHours = 10,
    initialMinutes = 0,
    initialSeconds = 0,
}) => {
    const [hours, setHours] = useState(initialHours);
    const [minutes, setMinutes] = useState(initialMinutes);
    const [seconds, setSeconds] = useState(initialSeconds);

    let myInterval;

    const startTimer = () => {
        myInterval = setInterval(() => {
            if (seconds > 0) {
                setSeconds(seconds - 1);
            }
            if (seconds === 0) {
                if (hours === 0 && minutes === 0) {
                    clearInterval(myInterval);
                } else if (minutes > 0) {
                    setMinutes(minutes - 1);
                    setSeconds(59);
                } else if (hours > 0) {
                    setHours(hours - 1);
                    setMinutes(59);
                    setSeconds(59);
                }
            }
        }, 1000);
        cancelTimer();
    };
    const cancelTimer = () => {
        return () => {
            clearInterval(myInterval);
        };
    };

    return (
        <div>
            <h1 className='timer'>
                {hours < 10 && hours !== 0 ? `0${hours}:` : hours >= 10 && `${hours}:`}
                {minutes < 10 ? `0${minutes}` : minutes}:
                {seconds < 10 ? `0${seconds}` : seconds}
            </h1>
            <button onClick={startTimer}>START</button>
            <button>PAUSE</button>
            <button>RESUME</button>
            <button onClick={cancelTimer}>CANCEL</button>
        </div>
    );
};

export default Timer;

I'm having trouble with the START button and this is what it looks like when I click on the START button multiple times: enter image description here

You'll notice that on the first click the number never continues to go down unless I click on the START button again and again but it would look like a broken slot machine. And if I hit on the CANCEL button, it should stop the timer and reset back to the set time, but it doesn't. I don't know how to solve the problem for this 2 buttons, and much more for the PAUSE and RESUME. I don't know how to make them work, too. Please help.

question from:https://stackoverflow.com/questions/65936096/fully-functioning-countdown-timer-using-react-hooks-only

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

As suggested by @Felix Kling you can try a different approach, to check why your code is not working check the below code, I've made some changes in your Timer component :

import React, { useState } from 'react';

const Timer = ({
    initialHours = 10,
    initialMinutes = 0,
    initialSeconds = 0,
}) => {
    const [time, setTime] = useState({
        h: initialHours,
        m: initialMinutes,
        s: initialSeconds,
    });

    const [timer, setTimer] = useState(null);

    const startTimer = () => {
        let myInterval = setInterval(() => {
            setTime((time) => {
                const updatedTime = { ...time };
                if (time.s > 0) {
                    updatedTime.s--;
                }

                if (time.s === 0) {
                    if (time.h === 0 && time.m === 0) {
                        clearInterval(myInterval);
                    } else if (time.m > 0) {
                        updatedTime.m--;
                        updatedTime.s = 59;
                    } else if (updatedTime.h > 0) {
                        updatedTime.h--;
                        updatedTime.m = 59;
                        updatedTime.s = 59;
                    }
                }

                return updatedTime;
            });
        }, 1000);
        setTimer(myInterval);
    };

    const pauseTimer = () => {
        clearInterval(timer);
    };

    const cancelTimer = () => {
        clearInterval(timer);
        setTime({
            h: initialHours,
            m: initialMinutes,
            s: initialSeconds,
        });
    };

    return (
        <div>
            <h1 className='timer'>
                {time.h < 10 && time.h !== 0
                    ? `0${time.h}:`
                    : time.h >= 10 && `${time.h}:`}
                {time.m < 10 ? `0${time.m}` : time.m}:
                {time.s < 10 ? `0${time.s}` : time.s}
            </h1>
            <button onClick={startTimer}>START</button>
            <button onClick={pauseTimer}>PAUSE</button>
            <button onClick={cancelTimer}>CANCEL</button>
        </div>
    );
};

export default Timer;
    

Explanation:

  1. in your startTimer function in the last line you're calling cancelTimer
  2. When you're working with hooks then keep in mind you won't get updated value of state variable until you use function inside a set function like I'm doing in setTime and in that callback, you'll get an updated value as a first parameter
  3. In cancelTimer method you're returning a function you've to call clearInterval also myInterval is undefined in cancelTimer so I've set it's value in state

For more information and other ways check this question


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...