I use a vanilla (+ Presence) Phoenix 1.5.8 application to run a LiveView which lists all current visitors:
lib/example_web/live/page_live.ex
defmodule ExampleWeb.PageLive do
use ExampleWeb, :live_view
alias Example.Presence
alias Phoenix.Socket.Broadcast
@impl true
def mount(_params, _session, socket) do
Phoenix.PubSub.subscribe(Example.PubSub, "room:lobby")
{:ok, _} = Presence.track(self(), "room:lobby", UUID.uuid4(), %{status: "user"})
socket =
assign(socket,
current_users: current_user_ids()
)
{:ok, socket}
end
@impl true
def handle_info(%Broadcast{event: "presence_diff"}, socket) do
socket =
assign(socket,
current_users: current_user_ids()
)
{:noreply, socket}
end
@impl true
def render(assigns) do
~L"""
<%= inspect(@current_users) %>
"""
end
defp current_user_ids() do
Presence.list("room:lobby")
|> Enum.filter(fn {_id, x} -> hd(x.metas).status == "user" end)
|> Enum.map(fn {k, _} -> k end)
end
end
Works without a problem. It displays a unique ID for all current visitors.
But I would like to move this to a LiveComponent. So here is my attempt to do so:
lib/example_web/live/page_live.ex
defmodule ExampleWeb.PageLive do
use ExampleWeb, :live_view
alias ExampleWeb.ChatComponent
@impl true
def render(assigns) do
~L"""
<%= live_component @socket, ChatComponent, id: 1 %>
"""
end
end
lib/example_web/live/components/chat_component.ex
defmodule ExampleWeb.ChatComponent do
use ExampleWeb, :live_component
alias Example.Presence
alias Phoenix.Socket.Broadcast
@impl true
def mount(socket) do
Phoenix.PubSub.subscribe(Example.PubSub, "room:lobby")
{:ok, _} = Presence.track(self(), "room:lobby", UUID.uuid4(), %{status: "user"})
{:ok, assign(socket, current_users: current_user_ids())}
end
@impl true
def update(assigns, socket) do
socket =
assign(socket,
current_users: current_user_ids()
)
{:ok, socket}
end
@impl true
def handle_info(%Broadcast{event: "presence_diff"}, socket) do
socket =
assign(socket,
current_users: current_user_ids()
)
{:noreply, socket}
end
def render(assigns) do
~L"""
<%= inspect(@current_users) %>
"""
end
defp current_user_ids() do
Presence.list("room:lobby")
|> Enum.filter(fn {_id, x} -> hd(x.metas).status == "user" end)
|> Enum.map(fn {k, _} -> k end)
end
end
It doesn’t work. Only one ID is displayed and that self updates every half a second or so.
Can this be done in a LiveComponent? What do I have to change?