Timer
Enlighten the "start" button to animate the timer. Changes in App.js:
@@ -1,6 +1,54 @@
+import { useEffect, useRef, useState } from "react";
import "./App.css";
+import { formatTime } from "./util";
+
+const POMODORO_SECONDS = 25 * 60;
function App() {
+ const [seconds, setSeconds] = useState(POMODORO_SECONDS);
+ const [ticking, setTicking] = useState(false);
+
+ useEffect(() => {
+ if (seconds === 0) {
+ stopTimer();
+ alarm();
+ }
+ }, [seconds]);
+
+ // use the `useRef` hook to create a mutable object that persists across renders
+ const intervalIdRef = useRef(null);
+
+ const startTimer = () => {
+ setTicking(true);
+ intervalIdRef.current = setInterval(() => {
+ setSeconds((prevSeconds) => prevSeconds - 1);
+ }, 1000);
+ };
+
+ const stopTimer = () => {
+ setTicking(false);
+ if (intervalIdRef.current) {
+ clearInterval(intervalIdRef.current);
+ }
+ };
+
+ const resetTimer = () => {
+ stopTimer();
+ setSeconds(POMODORO_SECONDS);
+ };
+
+ const toggleTimer = () => {
+ if (ticking) {
+ stopTimer();
+ } else {
+ startTimer();
+ }
+ };
+
+ const alarm = () => {
+ // TODO: play some sound
+ console.log("Time's up!");
+ };
return (
<div className="app">
<h1 className="app-name">
@@ -13,10 +61,15 @@ function App() {
<span className="segment right-seg">Break</span>
</div>
<div className="card">
- <h1 className="timer">25:00</h1>
- <button className="control-btn">Start</button>
+ <h1 className="timer">{formatTime(seconds)}</h1>
+ <button className="control-btn" onClick={toggleTimer}>
+ {ticking ? "Pause" : "Start"}
+ </button>
</div>
<div className="settings">
+ <span className="setting-btn" onClick={resetTimer}>
+ Reset
+ </span>
<span className="setting-btn">Settings</span>
</div>
</div>
The "tick-tock" is triggered by the setInterval()
global function.
This method returns an interval ID which uniquely identifies the interval, so you can remove it later by calling clearInterval()
.
The interval ID is shared between startTimer
and stopTimer
functions with the help of useRef
.
Tune App.css a little bit:
.settings {
display: flex;
- justify-content: flex-end;
+ justify-content: space-between;
}
Add a new file named util.js:
export function formatTime(seconds) {
const minutes = Math.floor(seconds / 60);
const remainingSeconds = seconds % 60;
const formattedMinutes = String(minutes).padStart(2, "0");
const formattedSeconds = String(remainingSeconds).padStart(2, "0");
return `${formattedMinutes}:${formattedSeconds}`;
}
Then you may click the "start" button and see it ticking.