refactor(web): typing no longer re-renders the composer model picker#22721

merged1
refactor/chat-composer-footer-controls
refactor/chat-composer-stable-controls
opened2d agobyJJulius Marminge
View on GitHubTwo-way sync enabledPR last imported 2d ago

Every keystroke in the composer re-rendered the model picker and the attach button, even though neither depends on the prompt.

The fix uses component boundaries, not stable-callback wrappers. This adds no useStableCallback uses; ChatComposer keeps the 34 it has on main.

  • ComposerModelPicker (in ComposerFooterControls.tsx) wraps ProviderModelPicker. It defines the single-model and multi-model toggle handlers itself, from the multi-model selections and their setter, selectedModelSelection, the instance entries, the model options and onProviderModelSelect. None of those change while you type, so the compiler keeps the handlers. ChatComposer builds the <ComposerModelPicker> element as its own const. The controls row around it is rebuilt on every keystroke because TraitsPicker takes prompt, but the picker element itself stays cached.
  • ComposerAttachButton owns the hidden file input and builds its change handler from addComposerAttachments and focusComposer.
mainthis PR
ChatComposer.tsx lines6,7006,640
Renders, 20 typed chars678 (22 commits)352 (22 commits)
ProviderModelPicker subtree renders21 + popover/tooltip children0
Attach button renders21 (button, tooltip, icon)21 (ComposerAttachButton alone)

Renders measured with the shared fiber counter (rc-init.js) on a seeded dev server: typing 20 characters into an existing thread's composer, median of 3 runs.

Still rendering on each keystroke:

  • ComposerAttachButton itself. addComposerAttachments gets a new identity on every keystroke because of the prompt-editing helpers it calls. Its tooltip, button and icon children no longer re-render.
  • TraitsPicker. It takes prompt to detect "ultrathink", which needs a change to TraitsPicker itself. Both are left for follow-ups.

Tests run: vp lint and vp fmt --check on the changed files, tsc-rs --noEmit for apps/web, and reactCompilerCoverage.test.ts for the changed files (0 bailouts).

🤖 Generated with Claude Code

Checks

All checks passed

Added 1 commit

  • refactor(web): typing no longer re-renders the composer model pickereb67900
Synced from GitHub

Approvability

Verdict: Approved at eb67900

Macroscope's review found this PR approvable — This is a localized web UI performance refactor that extracts existing model-picker and attachment-control logic without changing product defaults, APIs, or workflows. The runtime impact is limited and the existing behavior is preserved across the three touched components.

You can add or adjust custom eligibility rules. Learn more.

Synced from GitHub

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Path: .coderabbit.config.ts
  • Review profile: CHILL
  • Plan: Team
  • Run ID: 29f60211-d5b6-4b2c-ba6d-c286ca507d3c
📥 Commits

Reviewing files that changed from the base of the PR and between 8c483f867955bff4383fe6014589cab135984d68 and eb67900ea5954f10f1a98adeac3f7c12716a099a.

📒 Files selected for processing: 3
  • apps/web/src/components/chat/ChatComposer.tsx
  • apps/web/src/components/chat/ComposerAttachmentStrip.tsx
  • apps/web/src/components/chat/ComposerFooterControls.tsx

Limit details: You’ve used all 10 included reviews currently available.

📝 Walkthrough

ChatComposer now uses extracted components for model selection and file attachments. The model picker supports single- and multi-model selection. The attachment button handles file selection and refocuses the composer when no attachments are inserted.

Changes: Composer controls

Layer / File(s)Summary
Model picker behavior and integration
apps/web/src/components/chat/ComposerFooterControls.tsx, apps/web/src/components/chat/ChatComposer.tsx
ComposerModelPicker adapts model toggles and direct model changes for single- and multi-model selection. ChatComposer configures and renders the component.
Attachment button behavior and integration
apps/web/src/components/chat/ComposerAttachmentStrip.tsx, apps/web/src/components/chat/ChatComposer.tsx
ComposerAttachButton opens a multi-file picker, resets its input after selection, and refocuses the composer only when no attachments were inserted. ChatComposer renders the extracted button.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~15 minutes

Change: Refactor

Merge Risk: ⚪ Minimal · up to eb679

The composer controls retain their selection and attachment behavior. No identified issue prevents merging after normal checks.

Pre-merge checks: Passed 3 · Failed 1

Failed Failed checks: 1 warning

Check nameStatusExplanationResolution
Description checkWarningThe description explains the problem, implementation, measured results, remaining renders, and verification. It does not follow the required headings, provide the required issue or maintainer approval…Add the required Problem, Change, Scope and approval, and Verification sections. Link the triaged issue or explicit maintainer approval, or explain the applicable exemption. Add clear before-and-after screenshots and any needed interaction …
Passed Passed checks: 3 passed
Check nameStatusExplanation
Title checkPassedThe title clearly and concisely describes the main web refactor: typing no longer re-renders the composer model picker.
Linked Issues checkPassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes checkPassedCheck skipped because no linked issues were found for this pull request.
Full details: Description check

Explanation

The description explains the problem, implementation, measured results, remaining renders, and verification. It does not follow the required headings, provide the required issue or maintainer approval evidence, or include before-and-after screenshots for this UI change.

Resolution

Add the required Problem, Change, Scope and approval, and Verification sections. Link the triaged issue or explicit maintainer approval, or explain the applicable exemption. Add clear before-and-after screenshots and any needed interaction recording. Preserve the reported test commands and results.

✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Usage-based review receipt

Note

This review was completed with usage-based billing: files reviewed beyond your plan's included limits are billed at $0.25/file. View usage-based billing.

Comment @coderabbitai help to get the list of available commands.