8
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Phoenix LiveView:リンク・ナビゲーション

Last updated at Posted at 2020-10-02

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
      )
  )

以上

8
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?