I want to thank @Abdulmuhaymin for the insight a couple of days ago about web workers in my question. Unfortunately, I still haven't succeeded to implement the web workers to my react stopwatch so I tried another way, and it seems to work. I'm not sure whether this is the right way, so feedbacks would be helpful. Thanks in advance!
I added one more useEffect hooks, and make the mSec and sec state independent on their own setInterval, and the min state dependent on the sec's useEffect
import { useState, useEffect } from "react";
export const SW = () => {
const [mSec, setMSec] = useState(0);
const [sec, setSec] = useState(0);
const [min, setMin] = useState(0);
const [isOn, setIsOn] = useState(false);
const start = () => setIsOn(true);
const stop = () => setIsOn(false);
const reset = () => {
setIsOn(false);
setMin(0);
setSec(0);
setMSec(0);
};
useEffect(() => {
let ms;
if (isOn) {
ms = setInterval(() => setMSec((mSec) => mSec + 1), 10);
}
if (mSec === 100) {
setMSec(0);
}
return () => clearInterval(ms);
}, [mSec, isOn]);
useEffect(() => {
let s;
if (isOn) {
s = setInterval(() => setSec((sec) => sec + 1), 1000);
}
if (sec === 60) {
setSec(0);
setMin((min) => min + 1)
}
return () => clearInterval(s);
}, [sec, isOn]);
return (
<div>
<p>
{min.toString().padStart(2, "0")}:{sec.toString().padStart(2, "0")}:
{mSec.toString().padStart(2, "0")}
</p>
{!isOn && <button onClick={start}>{!mSec ? "start" : "resume"}</button>}
{isOn && <button onClick={stop}>stop</button>}
<button disabled={!mSec} onClick={reset}>
reset
</button>
</div>
);
};
edit: I just realize that the minutes movement doesn't seem related to the seconds movement, so I move the setInterval of min to the useEffect of sec and deleted the useEffect of min
edit 2: change the sec and mSec reset condition to 60 and 100