Repository navigation
fix: keep React updates from walking the whole editor while typing - #694
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Before every commit, React DOM saves the selection of the focused element when its
contentEditableproperty reads"true", counting text offsets over every node beneath it. While the editor had focus, each React commit therefore walked the whole document. In a release build ofmain, these commits happen while the editor has focus:StatusBaron every keystroke, inside the key's own task, for the word and character counts and the block path.HeadingOutlineabout one frame later on every keystroke when a heading follows the caret, since the headings' positions shift.Shellon the first edit and when the command state changes.ScrollAreawhen the view scrolls, including wheel scrolling.What changes:
contentEditablegetter that reports"inherit"where the element's value is"true", so React no longer treats the editor as selection-capable and skips the walk. Thecontenteditableattribute,isContentEditable, and editing are unchanged, and the plugin removes the property when the editor is destroyed.CHANGELOG.mdrecords the faster typing.Deferring the status bar and outline commits until typing pauses was rejected: it would delay what the user sees, and each deferred commit would still walk the document.
Related Issue
Closes #685
Verification
"true", a read-only editor reporting"false", and removal on destroy.pnpm check:frontendpassed.Manually verified in release builds on Windows 11, driven over the WebView2 DevTools protocol with the 1 MB code and table fixtures from #680:
A temporary React DevTools hook on
mainat 9aa80f9 recorded the commits listed in the Summary, every one with the editor focused.This change built on 9aa80f9 against the same build with only the plugin's registration removed, median of 5 keystrokes, script time and keystroke-to-paint in ms:
In CPU profiles of one keystroke per target, React's time fell from 49–87 ms, 44–74 ms of it in
commitBeforeMutationEffects, to 0–2.4 ms, and that function no longer appeared.On the branch, the status bar's character count rose by one with every keystroke.
Not verified: scrolling times, and timings after rebasing onto #693.
Notes
The fix depends on React DOM's
hasSelectionCapabilitiesreadingelem.contentEditable === "true"(React DOM 19.3.0). If React changes that check, the walk returns without breaking behavior, and the focused test fails. When a commit moves focus out of the editor, React still refocuses it but no longer sets the caret itself; the browser keeps the editor's own selection.