DEV Community

Discussion on: How To: Start & Stop Counter in React

Collapse
lukeshiru profile image
LUKESHIRU • Edited on

One thing you could do to make this more reusable is to put the logic for interval and the timer into custom hooks. So you'll have something like this for interval:

import { useEffect } from "react";

export const interval =
    (delay = 0) =>
    /** @param {() => void} callback */ callback =>
        useEffect(() => {
            const id = setInterval(callback, delay);

            return () => clearInterval(id);
        }, [callback]);
Enter fullscreen mode Exit fullscreen mode

This for the timer:

import { useCallback, useState } from "react";
import { interval } from "./interval";

const use1Second = interval(1e3);

export const useTimer = ({
    seconds: initialSeconds = 0,
    running: initiallyRunning = false
} = {}) => {
    const [seconds, setSeconds] = useState(initialSeconds);
    const [running, setRunning] = useState(initiallyRunning);
    const tick = useCallback(
        () => (running ? setSeconds(seconds => seconds + 1) : undefined),
        [running]
    );
    const start = () => setRunning(true);
    const pause = () => setRunning(false);
    const reset = () => setSeconds(0);
    const stop = () => {
        pause();
        reset();
    };

    use1Second(tick);

    return { pause, reset, running, seconds, start, stop };
};
Enter fullscreen mode Exit fullscreen mode

And finally, use them in your Timer component:

import { useTimer } from "./useTimer";

export const Timer = () => {
    const { seconds, start, stop } = useTimer();

    return (
        <div className="counter-container">
            <button className="start-button" onClick={start}>
                start
            </button>
            <button className="stop-button" onClick={stop}>
                stop
            </button>
            <p id="counter">{seconds}</p>
        </div>
    );
};
Enter fullscreen mode Exit fullscreen mode

Here's a live example:

Cheers!

Collapse
am20dipi profile image
Adriana DiPietro Author

Wow. Great ideas! You really dried up the code :)