I am new to react and decided to practice by implementing a simple stop watch using both class and functional components.
I successfully implemented the stop watch using a class component. Below is the code:
Class Component
class Stopwatch extends Component {
state = {
status: false,
ms: 0,
seconds: 0,
minutes: 0,
};
stopms;
stopSeconds;
stopMinutes;
handleClick = () => {
this.changeStatus();
if (this.state.status) {
clearInterval(this.stopms);
clearInterval(this.stopSeconds);
clearInterval(this.stopMinutes);
} else {
this.stopms = setInterval(this.changeMs, 1);
this.stopSeconds = setInterval(this.changeSeconds, 1000);
this.stopMinutes = setInterval(this.changeMinutes, 60000);
}
};
changeStatus = () => {
return this.setState((state) => {
return { status: !state.status };
});
};
changeMs = () => {
return this.setState((state) => {
if (state.ms === 99) {
return { ms: 0 };
} else {
return { ms: state.ms + 1 };
}
});
};
changeSeconds = () => {
return this.setState((state) => {
if (state.seconds === 59) {
return { seconds: 0 };
} else {
return { seconds: state.seconds + 1 };
}
});
};
changeMinutes = () => {
return this.setState((state) => {
if (state.seconds === 59) {
return { minutes: 0 };
} else {
return { minutes: state.minutes + 1 };
}
});
};
handleReset = () => {
clearInterval(this.stopms);
clearInterval(this.stopSeconds);
clearInterval(this.stopMinutes);
this.setState({ seconds: 0, status: false, minutes: 0, ms: 0 });
};
componentWillUnmount() {
clearInterval(this.stopms);
clearInterval(this.stopSeconds);
clearInterval(this.stopMinutes);
}
render() {
return (
<div>
<h1>
{this.state.minutes} : {this.state.seconds} .{" "}
<span>{this.state.ms}</span>
</h1>
<button className="btn btn-lg btn-dark" onClick={this.handleClick}>
{this.state.status === false ? "Start" : "Pause"}
</button>
<button className="btn btn-lg btn-dark" onClick={this.handleReset}>
Reset
</button>
</div>
);
}
}
export default Stopwatch;
Now I'm trying to implement the same code above but using a functional component as shown below:
Functional Component
function Stopwatch() {
const [timeState, setTimeState] = useState({
status: false,
ms: 0,
seconds: 0,
minutes: 0,
});
let stopms;
let stopSeconds;
let stopMinutes;
const handleClick = () => {
changeStatus();
if (timeState.status) {
clearInterval(stopms);
clearInterval(stopSeconds);
clearInterval(stopMinutes);
} else {
stopms = setInterval(changeMs, 1);
stopSeconds = setInterval(changeSeconds, 1000);
stopMinutes = setInterval(changeMinutes, 60000);
}
};
const changeStatus = () => {
return setTimeState((prevState) => {
return { ...prevState, status: !prevState.status };
});
};
const changeMs = () => {
return setTimeState((prevState) => {
if (prevState.ms === 99) {
return { ...prevState, ms: 0 };
} else {
return { ...prevState, ms: prevState.ms + 1 };
}
});
};
const changeSeconds = () => {
return setTimeState((prevState) => {
if (prevState.seconds === 59) {
return { ...prevState, seconds: 0 };
} else {
return { ...prevState, seconds: prevState.seconds + 1 };
}
});
};
const changeMinutes = () => {
return setTimeState((prevState) => {
if (prevState.seconds === 59) {
return { ...prevState, minutes: 0 };
} else {
return { ...prevState, minutes: prevState.minutes + 1 };
}
});
};
const handleReset = () => {
clearInterval(stopms);
clearInterval(stopSeconds);
clearInterval(stopMinutes);
setTimeState({ seconds: 0, status: false, minutes: 0, ms: 0 });
};
return (
<div>
<h1>
{timeState.minutes} : {timeState.seconds} . <span>{timeState.ms}</span>
</h1>
<button className="btn btn-lg btn-dark" onClick={handleClick}>
{timeState.status === false ? "Start" : "Stop"}
</button>
<button className="btn btn-lg btn-dark" onClick={handleReset}>
Reset
</button>
</div>
);
}
export default Stopwatch;
The Problem
In the class component, I implemented the "Pause" functionality using the handleClick function which calls clearInterval with it's argument as the global variables stopms, stopSeconds, stopMinutes that I declared initially. This worked just fine because these global variables were holding values returned from the respective setInterval when the stop watch started counting.
Now in the functional component, I replicated the same logic by declaring the same global variables using the "let" keyword. But the "Pause" functionality is not working. When the "Start" button hit and the handleClick function called, the setIntervals were called and their return values were stored in the respective global variables. But when the "Pause" button was hit, all the global variables had "undefined" as their values.
Please I would like to know if there's any other way I can declare global variables and use them to hold values throughout a component's life cycle asides using state.