re-read the clock when the window comes back

This commit is contained in:
pj committed 2026-09-03 11:22:44 +05:30
1 parent 9462b7920f
commit 17c3873723
1 file changed
+20 -9
+20 -9
View File
@@ -2,7 +2,10 @@
// line moves on, and the hour the fit holds open around it. // line moves on, and the hour the fit holds open around it.
// //
// Both schedule off the clock rather than off an interval, so a tab that was asleep and a machine // Both schedule off the clock rather than off an interval, so a tab that was asleep and a machine
// that woke up catch up on the next tick instead of drifting further out every hour. // that woke up catch up on the next tick instead of drifting further out every hour. A timer is
// still a timer, though: one set before the lid closed can fire long after its wall-clock
// deadline, and a hidden window's timers run late or not at all. So the window coming back, as a
// focus or a visibility change, is read as a tick of its own.
// //
// They are separate hooks because they are separate rerenders. The minute belongs to the one // They are separate hooks because they are separate rerenders. The minute belongs to the one
// component that draws the line; putting the fit on that tick would solve the whole axis sixty // component that draws the line; putting the fit on that tick would solve the whole axis sixty
@@ -32,16 +35,24 @@ function useTick<T>(read: (now: number) => T, next: (now: number) => number): T
let timer = 0; let timer = 0;
const schedule = () => { const schedule = () => {
const now = Date.now(); const now = Date.now();
timer = window.setTimeout( timer = window.setTimeout(tick, Math.max(0, next(now) - now));
() => { };
setValue(read(Date.now())); const tick = () => {
schedule(); window.clearTimeout(timer);
}, setValue(read(Date.now()));
Math.max(0, next(now) - now), schedule();
); };
const woke = () => {
if (document.visibilityState === "visible") tick();
}; };
schedule(); schedule();
return () => window.clearTimeout(timer); document.addEventListener("visibilitychange", woke);
window.addEventListener("focus", woke);
return () => {
window.clearTimeout(timer);
document.removeEventListener("visibilitychange", woke);
window.removeEventListener("focus", woke);
};
// Both callbacks are module-level functions in every caller, so there is nothing to rebind. // Both callbacks are module-level functions in every caller, so there is nothing to rebind.
}, [read, next]); }, [read, next]);
return value; return value;