Skip to content

Fix useLayoutEffect frame flicker#889

Open
sindresorhus wants to merge 1 commit into
masterfrom
fix-uselayouteffect
Open

Fix useLayoutEffect frame flicker#889
sindresorhus wants to merge 1 commit into
masterfrom
fix-uselayouteffect

Conversation

@sindresorhus
Copy link
Copy Markdown
Collaborator

Fixes #773

I'm not sure about it yet. It has some potential regressions in the tradeoffs. Feedback welcome.


How it works now:

  • On every interactive render to writable stdout, Ink does not write immediately.
  • Instead it stores the latest interactive output and accumulates any new output in pendingInteractiveFrame.
  • It schedules one microtask flush. In that flush it first settles throttled render work and runs flushSyncWork(), then writes one coalesced frame.
  • Before external writes (useStdout/useStderr), waitUntilRenderFlush, clear, and unmount, Ink force-flushes any pending frame so ordering stays correct.

How this fixes #773:

  • Previously only the first interactive frame was deferred. Later commits could still paint a pre-useLayoutEffect frame and then repaint, causing flicker.
  • Now every interactive commit uses the defer-and-coalesce path, so mount/remount/update commits only paint the post-layout settled frame.
  • <Static> still works because static chunks from deferred passes are accumulated and emitted once with the coalesced frame.

Tradeoffs:

  • Output timing is microtask-delayed instead of immediate synchronous writes; callers that depend on flush completion should await waitUntilRenderFlush().
  • Multiple commits in one tick may collapse into one frame, which removes flicker but hides intentional transient intermediate states.
  • There is small per-frame overhead from queueMicrotask plus sync flush before write.
  • Behavior differs between real writable streams (deferred path) and non-stream-like outputs used in some tests (sync path).
  • Render timing logic is more complex, so regressions are easier to introduce without focused tests.

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.

useLayoutEffect should execute immediately

1 participant