Fix focus change re-renders - #15624
Open
samhh wants to merge 2 commits into
Open
Conversation
Today I discovered that iterators are lazy, produce no intermediate allocations, and their creation is O(1) with only minor iteration overhead. They are similar to stream fusion in Haskell. This makes them a generally more performant, more readable - albeit more verbose - alternative to where I've abused flatMap as a filterMap. This commit is me playing with them. It's a minor improvement we may as well keep.
The previous implementation triggered a re-render of the PageBody component that consumes the calling hook. In certain very large repos this would cause the UI to lock up on every focus change. Whilst this performance problem was severely compounded by other performance issues to be addressed in due course, this is still a worthy fix.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR aims to reduce unnecessary re-renders in the Lite workspace UI (notably those triggered by focus changes) by removing focus-driven subscriptions and by replacing several array-building patterns with iterator-based pipelines to reduce intermediate allocations and identity churn.
Changes:
- Remove the
useActiveElementfocus subscription and compute focused scope at the time a hotkey is invoked. - Replace many
flatMap/array-materialization patterns with iterator pipelines (values(),map,filter,toArray) and add small iterator utilities (reverseValues,iteratorConcat). - Export a couple of previously-internal types (
CheckableAddress,CheckedConflict) to support new typing needs across workspace components.
Reviewed changes
Copilot reviewed 29 out of 29 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| apps/lite/ui/src/routes/project/$id/workspace/WorkspaceLists/WorkspaceLists.tsx | Switch stack/changes/address derivations to iterator pipelines; reverse stack traversal without cloning. |
| apps/lite/ui/src/routes/project/$id/workspace/WorkspaceLists/useStackMenuItems.ts | Build foldable ref list via iterators to avoid intermediate arrays. |
| apps/lite/ui/src/routes/project/$id/workspace/WorkspaceLists/commitTargetComboboxItems.ts | Build commit-target combobox items using reversed iteration + iterator filtering. |
| apps/lite/ui/src/routes/project/$id/workspace/useUpstreamList.ts | Refactor stack-branch extraction into iterator pipeline; adjust call site for optional headInfo. |
| apps/lite/ui/src/routes/project/$id/workspace/useCheckedActions.ts | Derive selected hunks via iterator map/filter instead of flatMap. |
| apps/lite/ui/src/routes/project/$id/workspace/Sidebar.tsx | Compute rebase updates inside the action and build them via iterators. |
| apps/lite/ui/src/routes/project/$id/workspace/Page.tsx | Remove focus subscription hook usage; compute focus scope on-demand in hotkey callback. |
| apps/lite/ui/src/routes/project/$id/workspace/FilesTree.tsx | Convert set-building and checked-path extraction to iterator pipelines. |
| apps/lite/ui/src/routes/project/$id/workspace/file-row.ts | Return file-row items as an iterator (via iteratorConcat) and materialize only where needed. |
| apps/lite/ui/src/routes/project/$id/workspace/diff-minimap.ts | Replace flatMap with iterator map/filter/toArray for selection endpoints. |
| apps/lite/ui/src/routes/project/$id/workspace/diff-line-target.ts | Replace flatMap with iterator helpers to locate the first line-number attribute. |
| apps/lite/ui/src/routes/project/$id/workspace/Details.tsx | Refactor multiple “derive collections” spots to iterator pipelines and tighten some types. |
| apps/lite/ui/src/routes/project/$id/workspace/DependencyIndicator.tsx | Build dependency tooltip set via iterator map/filter. |
| apps/lite/ui/src/routes/project/$id/workspace/ConflictBar.tsx | Build checked conflict mapping via iterator pipeline; add exported type dependency. |
| apps/lite/ui/src/routes/project/$id/workspace/CommitForm.tsx | Build commit change specs via iterator filtering instead of flatMap. |
| apps/lite/ui/src/routes/project/$id/workspace/CommandPalette.tsx | Accept iterables for grouping and use iteratorConcat to combine filtered items. |
| apps/lite/ui/src/routes/project/$id/workspace/BranchPicker.tsx | Produce branch picker options via iterator pipeline and materialize once. |
| apps/lite/ui/src/routes/project/$id/workspace/ApplyBranchPicker.tsx | Refactor option derivation/grouping to iterator pipelines (includes one runtime-compat concern). |
| apps/lite/ui/src/routes/project/$id/workspace/applied-address-space.ts | Use reverseValues to walk stacks in reverse without toReversed() cloning. |
| apps/lite/ui/src/routes/project/$id/workspace/AnnotationCard.tsx | Replace flatMap-based filtering with a type-narrowing filter. |
| apps/lite/ui/src/router.ts | Refactor query-string building to iterator filter/map/toArray pipeline. |
| apps/lite/ui/src/reconcile.ts | Refactor multiple checked-item derivations and query combine logic to iterators. |
| apps/lite/ui/src/projects/project.ts | Export CheckableAddress and CheckedConflict types for cross-module use. |
| apps/lite/ui/src/project-events.ts | Refactor integrated-review refresh collection building to iterator pipeline. |
| apps/lite/ui/src/native-menu.ts | Remove @public doc comments from exported menu helpers. |
| apps/lite/ui/src/iterator.ts | Add iterator utilities: iteratorConcat and reverseValues. |
| apps/lite/ui/src/hunk.ts | Refactor selection positioning derivation to iterator map/filter/toArray. |
| apps/lite/ui/src/focus.ts | Remove useActiveElement hook (and its focus event subscription). |
| apps/lite/ui/src/checking.ts | Refactor range construction to iterator drop/take pipeline feeding Set. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
samhh
enabled auto-merge
August 28, 2026 15:48
Member
|
@samhh sorry for the blockage. It is not fixed in the latest version of the app - so if you just rebase or edit something here, the committer will be fixed |
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.
Currently blocked from merging by this: #15612 (comment)
If someone with elevated permissions would like to merge please go ahead. 🙂