Skip to content

perf(commands): eliminate redundant search calls and double setState on item hover in CommandPalette and QuickSwitcher #1343

Description

@ZhuchkaTriplesix

Problem

In lib/features/command_palette/command_palette_dialog.dart and quick_switcher_dialog.dart:

  1. Double setState on mouse movement:
    In ListView.builder, each item defines:
onHover: (_) => setState(() => _selected = index),

In Flutter, InkWell.onHover fires with true on pointer enter and false on pointer exit. When moving the cursor between list rows, this triggers two consecutive setState calls (one for unhovering the old item, one for hovering the new item), rebuilding the entire dialog twice per item boundary without checking if (isHovered).

  1. Repeated search() evaluation:
    In CommandPaletteDialog, _hits is a computed getter:
List<QueryaCommand> get _hits {
  if (_objectPrefix) return const [];
  final ctx = widget.hostContext.mounted ? widget.hostContext : context;
  return QueryaCommandRegistry.instance.search(_controller.text, context: ctx);
}

It is called in _move(), in arrow navigation, and twice during build(). Because each mouse hover rebuilds the dialog, search() and string matching execute repeatedly on every pointer pixel movement.

Code Locations

  • lib/features/command_palette/command_palette_dialog.dart (lines 62–66, 161)
  • lib/features/command_palette/quick_switcher_dialog.dart (line 230)

UI Kit Relationship

  • Feature Component (Not UI Kit): These dialogs live in lib/features/command_palette/. They use the UI Kit modal shell (showAppDialog / QueryaDialogCard), but the list rows are implemented ad-hoc using raw material.InkWell and DecoratedBox.
  • No open issues currently track this hover/search overhead.

Proposed Solution

  1. Guard hover state updates so only positive enters update selection:
onHover: (hovered) {
  if (hovered && _selected != index) {
    setState(() => _selected = index);
  }
}
  1. Cache search results (_hits) on query change instead of re-evaluating the getter inside build().
  2. Consider using a localized ValueNotifier<int> for selection or item-level hover widgets so the parent dialog and search input do not rebuild on hover.

Acceptance Criteria

  • Pointer hovering over commands in Command Palette / Quick Switcher does not trigger redundant full dialog rebuilds.
  • QueryaCommandRegistry.instance.search is called only when the search query text changes or new commands are registered.

Activity

  1. added
    frontendTheme parser epic label: frontend
    performanceTheme parser epic label: performance
    uiUser interface components and widgets
    uxUser experience, keyboard shortcuts and interactions
    P3Low priority / Polish & Enhancements
    on Oct 10, 2026
  2. ZhuchkaTriplesix commented on Oct 11, 2026

    @ZhuchkaTriplesix
    MemberAuthor

    Done in #1426.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Low priority / Polish & EnhancementsfrontendTheme parser epic label: frontendperformanceTheme parser epic label: performanceuiUser interface components and widgetsuxUser experience, keyboard shortcuts and interactions

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions