この記事の途中に、以下の記事の引用を含んでいます。
Phoenix LiveView Colocated Hooks and JavaScript
シンプルで強力!LiveViewにやってきた「Colocated Hooks」とは?
ElixirでリアルタイムWebアプリ開発を可能にするPhoenix LiveView。
そのバージョン1.1から追加された「colocated JavaScript Hooks(コロケーテッド・フック)」が今、開発者のワークフローを大きく進化させています。
今回の記事は、この便利機能の概要と、どのような意義を持ち、実践でどう活用できるのかを解説します。
また、プロダクションコードで具体的にどう使うかも交えつつ、私自身の技術的考察もまとめています。
驚くほど簡単に拡張!Colocated Hooksの導入ポイント
まず、元記事では、colocated hookについてこう説明されています:
“A colocated hook lives alongside your component code. This makes writing simple hooks much easier. Instead of having to create a separate file, we can just add our hook to our HEEx component.”
この一文は、LiveViewコンポーネントのHTML(HEExテンプレート)内部に、そのままJavaScriptフックのコードを直接記載できるようになった、という意味です。
従来であれば、LiveViewコンポーネントと連携するJavaScriptフック(カスタムイベントリスナーなど)は、全てassets/jsのようなディレクトリに、ファイルを分けて記述し、それをアプリ側でリンクさせる必要がありました。
しかし、「colocated hooks」導入後は、その煩雑なファイル構成を気にせず、HEExファイルに <script :type={Phoenix.LiveView.ColocatedHook}> タグを使って直接JSを書くことができるのです。
これにより、JSフックを必要とするコンポーネントと、そのJSロジックが同じ場所で管理できるようになりました。
なぜ重要?SPA+リアルタイム時代の“分離と共存”の最適解
この仕組みがなぜ画期的なのか。
ポイントは2つ挙げられます。
1. コンテキストの一元管理による開発効率の大幅向上
“Separation of concerns(関心の分離)”はソフトウェア設計の王道ですが、実はフロントエンド・バックエンドの垣根が急速に曖昧になる近年、分けたことで生じるコスト(編集時の移動や知的コンテキストの切替)も増えていました。
特にLiveViewのように「サーバ駆動UI+スポット的なJS拡張(ボタンのコピーやUIアニメーションなど)」のケースは、「ちょっとしたJS」のためだけに、巨大な構成を設計しなければなりませんでした。
Colocated Hooksはこの課題に対する答えの一つです。
今や「ReactのHooks」や「VueのComposition API」でも、ロジックのローカル化、(巨大なstore管理やグローバルJSファイルの肥大化といった)“持て余した分離”が避けられる傾向にあります。
同様の悩みを、Elixir/Phoenixスタックも上手く受け止めてきたのです。
2. 型安全・再利用性を犠牲にしない柔軟な実装が可能に
もちろんこのアプローチが“なんでもJSをべた書き可能”という乱雑さにつながる恐れもあります。
ただ、Phoenix LiveViewは「特殊なタグ(type指定)」と「命名規則(.MyHookName)」によって、モジュールスコープを意識したうえで競合やバグを防止。
また、JSフックは「マウント時のみイベントをバインド」「他イベントを汚染しない」ため、グローバルに悪影響を与えにくい。
この設計思想が、RailsにおけるStimulusや、最近のTurboフレーム、さらにはNext.jsのServer Componentsにも通じる「サーバサイド+最小限のクライアントJS」という潮流によく合致しています。
実践でここがスゴイ!「アルバムリンクをワンクリックコピー」機能の例
では、実際にどんな風に利用できるのか。
今回の記事では、楽曲アルバムのページに「ワンクリックでURLをコピーするボタンを追加したい」というごくシンプルなUI要件を題材に、その実装が紹介されています。
その中の重要部分を引用します:
“We’re setting up a click event listener. When someone clicks the button, we use the browser’s clipboard API to copy the current page URL. Then we find that hidden ‘Copied’ text, show it for 2 seconds as feedback, then hide it again.”
この通り、UIボタン側には
html
<button phx-hook=".CopyLink" ...>
<!-- アイコンや "Copied" テキスト -->
</button>
を設置し、そのままHEEx内に下記のようなJS(Colocated Hook)を記述します。
“`html
“`
この構成により、
- どのコンポーネントがどのフック依存か明快
- クリックイベントやDOM構造の認識ズレが発生しづらい
- “この箇所にだけ必要なJS”を安全に導入
という、メリットを最大限活かせます。
さらなる拡張性──Colocated JSによるUI制御の新しい流れ
LiveView 1.1では「colocated hooks」だけでなく、「colocated JS」も導入されました。
これは、より一般的なJSスニペットの局所的な注入を可能にするもので、例えば「要約テキストの“全文表示/折りたたみ”」のような動的UIスイッチ構築にも活躍します。
記事にも以下のようなスニペットが紹介されています。
“`html
“`
このスタイルで“イベント検知→DOM操作”が可能に。
他のフレームワークで言う「ローカルなJSファイル」や「Svelteの