5
0

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 親LiveViewと子Live Componentの連携

Posted at

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に処理をたくす

子で処理できるようになったら、そのついでに親に処理を投げたい。
(ページレイアウトの変更など)

やり方

  1. 子のhandle_event内でsend self(), hogehoge を使う。
  2. 親の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の進化が楽しみ。

5
0
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
5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?