This question looks simple on first glance but is actually more complex than it seems.
setInterval’s delay is unreliable. The actual amount of time that elapses between calls to the callback may be longer than the given delay due to various reasons e.g. nested timeouts, inactive tabs, throttling (firefox), timeouts in Web Extension. Reference: https://developer.mozilla.org/en-US/docs/Web/API/Window/setTimeout#reasons_for_delays_longer_than_specified
useEffect is async, there will be a delay on click if you use it on the start/pause button
===
Below is a list of implementations, starting from a naive approach to an optimal appraoch.
| Version | Details | Links |
|---|---|---|
| v0 | unreliable setInterval |
demo |
| v1 | a trick is to use setInterval for time calculation, but Date.now() is inacurrate that affected by system clock change, also useEffect has a delay in start & pause button on click |
demo |
| v2 | keep using setInterval trick but minimize button click delay by using performance.now(), however still keep calling useEffect every 10ms |
demo |
| v3 | use requestAnimationFrame instead of setInterval |
demo |
| v4 | final version | demo |
On the other side, in Valiina Javascript
| Version | Details | Links |
|---|---|---|
| v0 | setInterval |
demo |
| v1 | requestAnimationFrame |
demo |