Skip to content

fix: refresh the shared clock when the first component subscribes again - #517

Merged
brendt merged 1 commit into
dev-null-sh:productionfrom
jubianchi:fix/use-now-refresh-on-resubscribe
Oct 20, 2026
Merged

brendt merged 1 commit into
dev-null-sh:productionfrom
jubianchi:fix/use-now-refresh-on-resubscribe

Conversation

@jubianchi

Copy link
Copy Markdown
Contributor

Problem

useNow keeps a module-level now and runs its 30 s interval only while a component is subscribed. When the last subscriber unmounts, the interval stops; the next subscription restarted it without reading the clock, so now kept its old value until the first tick.

Inertia keeps module state across navigations. Spend a few minutes on a page without timestamps (Appearance, Terminal, Safety, About, Terms, Privacy), come back to the log, and for up to 30 s every relative age is behind by the time spent away: a commit posted meanwhile shows "now", older ones look younger, poll countdowns are stretched, then everything jumps at once.

Local check, back from Terminal after ~2 min, Remotes chat undocked (the dock keeps a subscriber alive):

Commit age at first render Before After
65 s now 1m
~5 min 4m 5m

Changes

  1. subscribe reads Date.now() when it restarts the interval. One line.
  2. tests/Unit/UseNow.test.tsx: mocked useSyncExternalStore and fake timers; subscribe, unsubscribe, move the clock ten minutes, subscribe again, tick once. Red before, green after.
  3. The test is listed in tests/draft-images.config.ts and tests/tsconfig.json; trivial conflict with test: run the ten component tests that CI never ran #492, which replaces those lists by globs.

Out of scope, noted for later: with SSR enabled (config/inertia.php), the same module value is the render server's start time until hydration replaces it.

@jubianchi
jubianchi marked this pull request as ready for review October 18, 2026 21:27
@jubianchi
jubianchi force-pushed the fix/use-now-refresh-on-resubscribe branch from b593949 to 37e4229 Compare October 19, 2026 19:42
The `useNow` store keeps a module-level `now` and runs its 30 s interval
only while at least one component is subscribed. When the last subscriber
unmounts, the interval stops, and the next subscription restarted it
without reading the clock: `now` kept the value of the moment the interval
stopped until the first tick.

Inertia keeps module state across navigations, so after a few minutes on a
page without timestamps (Appearance, Terminal, Safety, About, Terms,
Privacy) and back to the log, every relative age was behind by the time
spent away for up to 30 s: commits posted meanwhile showed "now", older
ones were rejuvenated, poll countdowns were stretched, and then everything
jumped at once on the first tick.

Read the clock again when the interval is restarted, so the first render
after coming back is right away. The test drives the hook through a mocked
`useSyncExternalStore` with fake timers: subscribe, unsubscribe, move the
system clock ten minutes, subscribe again and expect the new time, then
tick once to cover the interval.

🤖 Generated with Claude Code
@jubianchi
jubianchi force-pushed the fix/use-now-refresh-on-resubscribe branch from 37e4229 to 59fe98d Compare October 20, 2026 09:02
@jubianchi
jubianchi marked this pull request as draft October 20, 2026 09:02
@jubianchi
jubianchi marked this pull request as ready for review October 20, 2026 09:03
@brendt
brendt merged commit eeff1fb into dev-null-sh:production Oct 20, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants