Phoenixは通常セッションをPlug.Connを用いて扱いますが、LiveViewでUIを開発する場合はWebSocketでの通信となるため、Phoenix.LiveView.Socketが使われます。
WEBアプリケーションを開発する上でナビゲーションバーは必要不可欠かと思いますが、Plug.ConnとPhoenix.LiveView.Socketを両方使用するとナビゲーションバーで状態を保つことが難しいように感じるのではないでしょうか。例えば選択中のタブを他のタブメニューとは色分けするなど。
しかし、live_session/3の導入とともに上記の問題が解決されつつあります。
live_session/3はLiveViewのライフサイクルでマウントされる前に任意の処理を追加できるようにする関数です。
つまりナビゲーションメニューをクリックしたらLiveViewがマウントされる前に認証をしたり、選択されたメニューをsocketにアサインしたりすることができるようになります。
やり方はとても簡単です。
- layout/live.html.heexにナビゲーションバーを挿入
- attach_hook/4でactive_tabをsocketにアサイン
- router.exでactive_tabをアサインするモジュールをlive_sessionに追加
という3ステップでできます。
layout/live.html.heexにナビゲーションバーを挿入
テンプレートのapp.html.heexはPlug.Connでセッションが行われるため、LiveViewは使用できません。
しかし、live.html.heexであればLiveViewのライフサイクルに関与するため、socketに選択中のメニューをアサインすることができます。
<nav>
<div class="user_menu">
<div class="menu_container">
<a href="/" class="logo">logo</a>
<a href="/hoge" class="nav_menu" style={if @active_tab == :hoge, do: "background-color: rgb(160, 225, 235);"}>hoge</a>
<a href="/fuga" class="nav_menu" style={if @active_tab == :fuga, do: "background-color: rgb(160, 225, 235);"}>fuga</a>
</div>
</div>
<div class="icon_menu">
<div><%= @current_user.name %></div>
</div>
</nav>
attach_hook/4でactive_tabをsocketにアサイン
active_tabをアサインするモジュールを作成します。
defmodule HogeWeb.Nav do
import Phoenix.LiveView
def on_mount(:default, _params, _session, socket) do
{:cont,
socket
|> attach_hook(:active_tab, :handle_params, &set_active_tab/3)}
end
defp set_active_tab(params, _url, socket) do
active_tab =
case {socket.view, socket.assigns.live_action} do
{HogeLive, _} -> :hoge
{FugaLive, _} -> :fuga
{_, _} -> nil
end
{:cont, assign(socket, active_tab: active_tab)}
end
end
router.exでactive_tabをアサインするモジュールをlive_sessionに追加
#...
live_session :authenticated, on_mount: [HogeWeb.Nav] do
live "/hoge", HogeWeb.HogeLive
live "/fuga", HogeWeb.FugaLive
end
#...
このような手順でナビゲーションバーがLiveViewで作成できるようになります。
参考文献
この記事はFly.ioのブログで紹介されていた記事の内容を参考させていただきました。
Active nav with LiveView