0

我对 Phoenix LiveView 组件 (v0.15.4) 有疑问。

在文档中,有一个示例代码:

def handle_info({:updated_card, card}, socket) do
  send_update CardComponent, id: card.id, board_id: socket.assigns.id
  {:noreply, socket}
end

LiveView 组件没有handle_info/2回调,因此send_update/3被调用以将事件从父 LiveView 重定向到特定组件。

但是,我想将事件直接从父 LiveView 发送到特定组件,因为我想做这样的事情

# parent LiveView
def handle_info({:new_card, card_id}, socket) do
  send_event CardStackComponent, id: :card_stack, event: "add_card", params: %{"card_id" => card_id}
  {:noreply, socket}
end

# component
def handle_event("add_card", %{"card_id" => card_id} = _params, socket) do
  card = get_card(card_id)

  socket =
    update(socket, :cards, fn cards ->)
      [card | cards]     
    end)
    
  {:noreply, socket}
end

当然,没有Phoenix.LiveView.send_event/2. 以上是一个虚构的代码来说明我的意图。

phx-target="<%= @myself %>"我知道如何通过将属性添加到 HTML 元素或使用pushEventToJavaScript 程序中的方法将事件从客户端(浏览器)发送到特定组件。

但是,据我所知,没有办法将事件直接从父 LiveView 发送到特定组件。

有什么解决方法或更好的方法吗?

4

2 回答 2

1

Phoenix Pubsub就是答案。

defmodule QuickPick.Cards.LiveUpdates do
  @topic inspect(__MODULE__)

  @doc "subscribe for all cards"
  def subscribe_live_view do
    Phoenix.PubSub.subscribe(QuickPick.PubSub, topic(), link: true)
  end

  @doc "subscribe for specific card"
  def subscribe_live_view(card_id) do
    Phoenix.PubSub.subscribe(QuickPick.PubSub, topic(card_id), link: true)
  end

  @doc "notify for all cards"
  def notify_live_view(message) do
    Phoenix.PubSub.broadcast(QuickPick.PubSub, topic(), message)
  end

  @doc "notify for specific card"
  def notify_live_view(card_id, message) do
    Phoenix.PubSub.broadcast(QuickPick.PubSub, topic(card_id), message)
  end

  defp topic, do: @topic
  defp topic(card_id), do: topic() <> to_string(card_id)
end

订阅并处理更新

def mount(session, socket) do
  LiveUpdates.subscribe_live_view(card.id)
  ...
end

def handle_info({_requesting_module, [:recommendations, :updated], []}, socket) do
  ...
end

更新

LiveUpdates.notify_live_view(
  card.id,
  {__MODULE__, [:recommendations, :updated], []}
)
于 2021-04-14T15:54:32.493 回答
0

你也可以

# parent LiveView
def handle_info({:new_card, card_id}, socket) do
  send_update CardStackComponent, id: :card_stack, card_id: card_id
  {:noreply, socket}
end

#component
def update(%{card_id: card_id} = _assigns, socket) do
  card = get_card(card_id)

  socket =
    update(socket, :cards, fn cards ->
      [card | cards]     
    end)
  {:ok, socket}
end

您必须记住,update/2每次渲染都会调用它。更多关于这里的信息

还值得一提的是,您可能希望在 LiveView 或 LiveComponent 中保持状态,但不能同时在两者中保持状态,如此处所述

于 2022-02-08T15:26:15.230 回答