TypeScriptのイベントデリゲーション完全入門|DOM再描画で壊れない書き方

プログラミング学習

「ボタンを動的に追加したら、クリックイベントが効かなくなった」
「配列を更新して再レンダリングしたら、イベントが消えた」
TypeScriptやJavaScriptでDOM操作を学び始めると、誰もが一度はぶつかる壁です。

私自身、これまで肉体労働中心の仕事をしてきましたが、未経験からIT企業への転職が決まり、TypeScriptを学ぶことになりました。
正直、最初は「イベントリスナーって、ボタンに直接つけるだけじゃないのか?」という状態でした。

しかし実際にToDoリストのようなUIを作ってみると、
「なぜイベントデリゲーションが必要なのか」
「なぜ配列を更新するとイベントが消えるのか」
という疑問に直面します。

この記事では、TypeScriptでイベントデリゲーションが必要になる理由と、実際のコードをもとにした実装イメージを、初心者目線で整理します。

結論から言うと、「UIを作り直す前提の設計」にイベントデリゲーションは必須です。


TypeScriptでイベントデリゲーションが必要な理由

そもそもイベントデリゲーションとは何か

イベントデリゲーションとは、
子要素に直接イベントを付けず、親要素にまとめてイベントを付与する方法です。

クリックされた要素を event.target から判別することで、
動的に追加・削除される要素にも対応できるようになります。

これは、静的なHTMLだけを扱っているときには、なかなか実感しづらい考え方です。


配列の再レンダリングでイベントが消える理由

ToDoリストのようなアプリでは、

  • タスクを配列で管理
  • 配列をもとにDOMを作り直す

という流れがよく使われます。

今回のコードでも、以下のように 一度すべての要素を削除してから再生成 しています。

document.querySelectorAll("p").forEach((p) => p.remove());

この時点で、もし各ボタンに直接 addEventListener を付けていた場合、
DOMを削除した時点でイベントも一緒に消えます

つまり、
「見た目は同じボタンが再生成されているが、以前のボタンとは別物」
という状態になります。

この問題を避けるために使うのが、イベントデリゲーションです。


実装例で理解するイベントデリゲーション

親要素にイベントを付与する

今回のコードでは、ToDoリスト全体を包む div#all_list にイベントを設定しています。

all_l.addEventListener('click',(e)=>{
  const comp = e.target as HTMLElement;
  const idNum = Number(comp.id.replace("comp-", ""));
  comp_task(idNum);
},false);

この書き方のポイントは次の通りです。

  • クリックイベントは 親要素1ヶ所だけ
  • 実際に押されたボタンは e.target から取得
  • id の文字列を加工して、処理対象を特定

どのボタンが押されるかわからない時のID取得

イベントデリゲーションでは、
「次にどのボタンが押されるか分からない」
という前提で設計します。

そのため、ボタン作成時に ルールのあるid を付けています。

comp_btn.id = `comp-${Arr[i].id}`;
dele_btn.id = `dele-${Arr[i].id}`;

そしてクリック時に、文字列を加工して数字部分を取り出します。

const idNum = Number(comp.id.replace("comp-", ""));

この書き方を覚えると、

  • 完了ボタン
  • 削除ボタン
  • 動的に増える要素

すべてを1つのイベントで制御できるようになります。


DOMを全削除して再描画する設計

今回のコードでは、表示更新のたびに以下の流れを取っています。

  1. 既存のDOMをすべて削除
  2. 配列の状態をもとにDOMを作成
  3. 親要素にまとめたイベントで操作

これは一見すると乱暴に見えますが、
状態(配列)と表示(DOM)を分離する という点で、とても重要な考え方です。

Reactなどのライブラリが内部で行っている考え方にも近く、
「UIは状態の結果として作られるもの」という感覚を掴みやすくなります。


オブジェクトと型定義が効いてくる場面

今回のToDoリストでは、タスクをオブジェクトで管理しています。

type task = {
  id: number;
  theme: string; 
  done: boolean;
}

この型を定義しておくことで、

  • タスクの構造が明確になる
  • done の true / false が一目でわかる
  • イベント処理時に意図しない値を防げる

といったメリットがあります。

イベントデリゲーションはDOM操作の話ですが、
その裏ではオブジェクトと配列設計が非常に重要 だと実感しました。


まとめ

TypeScriptでイベントデリゲーションを使う理由は、
単に「便利だから」ではありません。

  • 配列を更新してDOMを再生成する
  • UIを状態の結果として扱う
  • イベントが消える問題を防ぐ

これらを自然に解決するための設計です。

未経験からTypeScriptを学んで感じたのは、
イベントデリゲーションは「テクニック」ではなく「考え方」 だということです。

小さなToDoリストでも、この考え方を押さえておくと、
今後ReactやVueを学ぶ際にも理解が一気に楽になります。

コメント

タイトルとURLをコピーしました