Create Branch

責務を理解して実装を心がけよう

Published on 2025年9月17日

つぶやき

はじめに

久しぶりの投稿です、最近はとても楽しく開発と勉強を進めつつ、個人プロダクトの基盤整備のため、MVPから見直して少しづつ進捗が出てきたとこ露です。
また、所属企業でチーム開発は難しいなと感じながらも、ユーザーへの価値提供を基準に何が必要か、意思決定が下せるようになってきたのは成長かなと感じます。

本題に入ります、とあるプロジェクトで発生していたエラー事象について学んだことをこちらに記載します。

結論

UIライブラリの責務を理解して、各UIライブラリの想定しているユースケースに沿って実装しよう。

🚨 発生した問題

企業検索機能で、**一文字目に a, b, c を入力すると選択不可になる**謎のバグが発生
こちらはとある実装を確認した時に発生していた事象です。

// 問題のあった実装
<DropdownMenu>
   <DropdownItem key="search">
        <Input placeholder="企業を検索..." />
   </DropdownItem>
   {companies.map(company => (
     <DropdownItem key={company.id}>{company.name}</DropdownItem>
))}
</DropdownMenu>

---

🔍 根本原因:内部制御との衝突

DropdownMenuの内部実装

// HeroUIが内部で自動実行(開発者は制御不可)
const handleKeyDown = (event) => {
const key = event.key.toLowerCase();
// 該当項目を自動検索・選択
const matchingItem = items.find(item =>
    item.textContent.toLowerCase().startsWith(key)
);
if (matchingItem) {
    setSelectedItem(matchingItem); // 🔥 自動選択
    scrollIntoView(matchingItem);   // 🔥 自動スクロール
}};

衝突の流れ

ユーザーが 's' を入力
     ↓
DropdownMenu内部「's'で始まる項目を選択!」
     ↓
Input「検索文字として's'を入力!」
     ↓
制御権の奪い合い → 選択不可状態 💥

⚡ heroui/DropdownMenuの本来の責務

設計思想:**選択専用**コンポーネント

  • キーボードナビゲーション機能が**内蔵**
  • 「選択肢から選ぶ」ための最適化
  • 検索機能は**想定外の用途**

内部で自動制御される機能

  • キーボードイベントの捕捉

  • 該当項目の検索ロジック

  • 選択状態の自動変更

  • フォーカス管理

    → 開発者が制御できない領域で勝手に動作

---

💀 無理やり修正の沼

内部制御を止めようと、どんどん複雑な実装に...

<DropdownMenu>
  <DropdownItem key="search" selectionMode="none"  // 選択機能を無効化>
    <Input  onKeyDown={(e) => e.stopPropagation()} // イベント伝播を遮断ref={inputRef/>
  </DropdownItem>
    {/* setTimeout でフォーカス制御の奪い返し... */}
</DropdownMenu>

なぜ複雑になるのか?

  • 内部制御との戦い = 設計思想に逆らった実装

  • 1つの回避策 → 新たな問題 → さらなる回避策...

    複雑な回避策 = 設計の問題のサイン ⚠️

---

✨ 正しい解決策

HeroUIのAutocompleteを使用

// シンプルで自然な実装
<Autocomplete placeholder="企業を検索..." onInputChange={handleSearch} onSelectionChange={handleSelect}>
  {companies.map(company => (
    <AutocompleteItem key={company.id}>
      {company.name}
    </AutocompleteItem>
  ))}
</Autocomplete>

なぜAutocompleteが正解?

  • 検索機能が**設計段階から組み込み済み**
  • キーボード入力は検索に専念(内部制御が適切)
  • 直接入力と選択の両方をサポート

設計思想に沿った自然な実装

📚 学んだ教訓

1. コンポーネントの責務を理解しよう

  • DropdownMenu = 選択専用(内部でキーナビゲーション制御)
  • Autocomplete = 検索+選択(内部で検索制御)

2. 内部制御を意識した選択

UIライブラリは「見た目」だけでなく「振る舞い」も提供

3. 適材適所の重要性

  • 「なぜこのコンポーネントが存在するのか?」を考える

4. 複雑な回避策は危険信号

無理な実装 → 内部制御との戦い → バグの温床 → 技術的負債

hirotobeat