1import React, { useState, useEffect } from 'react';
2
3const Timer = () => {
4 const [seconds, setSeconds] = useState(0);
5 const [isActive, setIsActive] = useState(false);
6
7 function toggle() {
8 setIsActive(!isActive);
9 }
10
11 function reset() {
12 setSeconds(0);
13 setIsActive(false);
14 }
15
16 useEffect(() => {
17 let interval = null;
18 if (isActive) {
19 interval = setInterval(() => {
20 setSeconds(seconds => seconds + 1);
21 }, 1000);
22 } else if (!isActive && seconds !== 0) {
23 clearInterval(interval);
24 }
25 return () => clearInterval(interval);
26 }, [isActive, seconds]);
27
28 return (
29 <div className="app">
30 <div className="time">
31 {seconds}s
32 </div>
33 <div className="row">
34 <button className={`button button-primary button-primary-${isActive ? 'active' : 'inactive'}`} onClick={toggle}>
35 {isActive ? 'Pause' : 'Start'}
36 </button>
37 <button className="button" onClick={reset}>
38 Reset
39 </button>
40 </div>
41 </div>
42 );
43};
44
45export default Timer;
46
1const Clock = ({ dispatch, inProgress, ticksElapsed }) => {
2 React.useEffect(() => {
3 const progressTimer = setInterval(function () {
4 inProgress && dispatch({ type: 'CLOCK_RUN' });
5 }, 500);
6 return () =>
7 //inprogress is stale so when it WAS true
8 // it must now be false for the cleanup to
9 // be called
10 inProgress && clearInterval(progressTimer);
11 }, [dispatch, inProgress]);
12
13 return <h1>{ticksElapsed}</h1>;
14};
15
16const App = () => {
17 const [inProgress, setInProgress] = React.useState(false);
18 const [ticksElapsed, setTicksElapsed] = React.useState(0);
19 const dispatch = React.useCallback(
20 () => setTicksElapsed((t) => t + 1),
21 []
22 );
23 return (
24 <div>
25 <button onClick={() => setInProgress((p) => !p)}>
26 {inProgress ? 'stop' : 'start'}
27 </button>
28 <Clock
29 inProgress={inProgress}
30 dispatch={dispatch}
31 ticksElapsed={ticksElapsed}
32 />
33 </div>
34 );
35};
36ReactDOM.render(<App />, document.getElementById('root'));