Phoenix LiveView コンポーネント親子間の連携
LiveViewいいですね!
docsに書いてあったけど、少し行き詰まったので、復習がてらメモ。
問題
子コンポーネントでhandle_eventしようとしたが、親コンポーネントにイベントが行ってしまう。
defmodule PakaWeb.Live.HeroComponent do
use Phoenix.LiveComponent
def render(assigns) do
Phoenix.View.render(PakaWeb.LiveView, "hero_component.html", assigns)
end
def mount(params, _session, socket) do
{:ok, assign(socket, query: "", message: "[Init-child]")}
end
# ここで処理したかった。が、来ない。
def handle_event("menu", query, socket) do
IO.inspect socket
{:noreply, update(socket, :message, fn x -> "pakaだよーbakaじゃないよ" end)}
end
end
子には来ないで、親の方のhandle_eventで処理されてしまう。
[error] GenServer #PID<0.717.0> terminating
** (FunctionClauseError) no function clause matching in PakaWeb.Live.Index.handle_event/3
親の方にhandle_eventを移植すると動きました。
しかし、子で処理して必要なものだけ親に委ねたい。
原因
statefulな子コンポーネントのidが未設定。
leexの方で、phx-clickとともにphx-targetを設定する。
phx-tagetのidは、子コンポーネントのrenderするleexのidにしたらうまくいった。
<section class="hero" id="hero"> // ここのid
// 省略
<div class="container">
<ul>
<li class="is-active"><a>Coffee</a></li>
<li ><a phx-click="menu" phx-target="#hero">Menu</a></li>
// このphx-targetが必要
<li><a>Access</a></li>
<li><a>Blog</a></li>
</ul>
</div>
</nav>
</div>
<section>
これで、うまくいった。
子コンポーネントから親LiveViewに処理をたくす
子で処理できるようになったら、そのついでに親に処理を投げたい。
(ページレイアウトの変更など)
やり方
- 子のhandle_event内でsend self(), hogehoge を使う。
- 親のhandle_infoで受け取る。
defmodule BunkadoWeb.Live.HeroComponent do
use Phoenix.LiveComponent
# 省略
def handle_event("menu", query, socket) do
send(self(), {:menu, "menu 押されたよ!親に送るね"})
{:noreply, update(socket, :message, fn x -> "子の処理" end)}
end
end
defmodule PakaWeb.Live.Index do
use Phoenix.LiveView
# 省略
# ここで親は受け取る。
def handle_info({:menu, message}, socket) do
IO.puts "親で受け取ったよ!やったね!#{message}"
{:noreply, assign(socket, message: message)}
end
end
おわりに
すごく久しぶりに時間が取れてコードかけたんですが、elixirは何を書いていたのかすぐ思い出せました。
Vueのprops使う連携より書きやすい気がしました。
Phoenix LiveViewの進化が楽しみ。