The Pagmatic Studioというサイトが無料のLiveViewのオンラインコースを提供しているので、それを教材としてLiveViewを勉強している。
そこでリンク・ナビゲーションが若干ややこしく感じたので、頭を整理しながらこのテーマに焦点を絞り、ざっくりまとめてみようと思う。
コードサンプルは、架空のguitarsデータベーステーブルが存在しそれのINDEXとSHOWページに取り組む前提で作成。
ルーティング
ルーティングは、Phoenix.LiveView.Router.live/4を使用して、MVCと同じ要領で定義する。
live "/guitars", GuitarLive
リンク・ナビゲーション
ざっくり3パターンをメモる。他にあれば、後で追加する。
A: 普通のHTMLアンカータグ
- クリックすると、HTTPリクエストが発生し、新たにLiveViewプロセスがspawnされる。
- LiveViewを使用しているのであれば、普通これは避けたいと思う。
B: phx-click
をもつHTMLアンカータグ
- フルリロードなしに画面が更新される。
- URLは更新されない。
テンプレート
アンカータグに下記の属性を付加する。
phx-click="任意のLiveViewイベント名"
-
phx-value-XXX="任意の値"
(XXXは任意のキー)
<nav>
<%= for guitar <- @guitars do %>
<a href="#" phx-click="show_guitar" phx-value-id="<%= guitar.id %>">
<%= guitar.name %>
</a>
<% end %>
</nav>
サーバー
handle_event
でLiveViewイベントを処理し、ソケットの状態を更新。その状態変化を元に差分が計算され、画面が更新される。
def handle_event("show_guitar", %{"id" => id}, socket) do
id = String.to_integer(id)
guitar = Guitar.get_guitar!(id)
socket = assign(socket, selected_guitar: guitar)
{:noreply, socket}
end
C: live_patch
により生成されるHTMLアンカータグ
- フルリロードなしに画面が更新される。
- URLも更新可能。
テンプレート
<nav>
<%= for guitar <- @guitars do %>
<%= live_patch guitar.name,
to:
Routes.live_path(
@socket,
__MODULE__,
id: guitar.id
),
replace: true
%>
<% end %>
</nav>
live_patch
により生成されたアンカータグには、/guitars?id=123
みたいなhref
の他に2つの特別な属性が付加される。
data-phx-link
data-phx-link-state
<a data-phx-link="patch" data-phx-link-state="replace" href="/guitars?id=123" replace="">
Fernandes APG-100
</a>
クリックするとLiveViewのJavaScriptが、DOMクリックイベントをインターセプトし、LiveViewイベントをサーバーにプッシュする。
サーバー
- LiveViewイベントは
handle_params
で処理する。 - (必要に応じてのみ呼び出される
handle_event
とは異なり)handle_params
はマウント後に呼び出され、live_patch
が使用されるたびに呼び出されるので、URLをコピーして新たに開いたブラウザに貼り付けても機能する。 - URLパラメータを受け取る場合は、パターンマッチングで値を取得する。
- URLパラメータがない場合に備えキャッチオールも用意しておく。
# URLパラメータがマッチする場合
def handle_params(%{"id" => id}, _url, socket) do
id = String.to_integer(id)
guitar = Guitar.get_guitar!(id)
socket = assign(socket, selected_guitar: guitar)
{:noreply, socket}
end
# URLパラメータがない場合、もしくはマッチしない場合
def handle_params(_params, _url, socket) do
{:noreply, socket}
end
LiveViewの処理の流れ
- 1: LiveViewイベントがWebSocket経由でブラウザからサーバーにプッシュされる。
- 2:
handle_params
が呼び出され、URLパラメータに基づいて状態が更新される。 - 3: ビューの差分がサーバーからブラウザにプッシュされる。
- 4: LiveViewのJavaScriptが、ブラウザのURLを変更し、ブラウザのPush StateAPIを使用してブラウザの履歴にURLを追加する。
D: サーバー主導でlive_patch
したい場合(push_patch
)
socket =
push_patch(socket,
to:
Routes.live_path(
socket,
__MODULE__,
id: guitar.id
)
)
以上