I have a chat app I’m building to test liveview. Right now I’m loading everything in a single liveview. All the messges, etc. When a message changes, I broadcast to chat:id
and listed for it, then I map over the messages, and update them if the change is specific to a message. This leads to a lot of re-render and seems inefficient. If I use temporary_assigns: [messages: []]
, then an update to a message (i.e. it get’s liked), doesn’t work since the message no longer exists.
My plan is to instead only listen to chat level changes in the main LiveView, and render N MessageComponents in a LiveView.Component. In each component’s mount, I’ll subscribe to message:id
, and then broadcast message changes that way. I’m hoping this will lead to less re-rendering of the entire message list. Right now a message like leads to an entire re-render of the message list, and not just the single message component. The issue is, the only assigns in the socket once the components mount is called are: assigns: %{flash: %{}, myself: 0},
.
Here’s some of the code:
View:
<%= for message <- @messages do %>
<%= live_component @socket, MyAppWeb.MessageComponent, Map.merge(assigns, %{id: message.id}) %>
<% end %>
MessageComponent
defmodule MyAppWeb.MessageComponent do
def render(assigns) do
MyAppWeb.ChatView.render("message.html", assigns)
end
def update(assigns, socket) do
socket =
assign(socket, %{
id: assigns.id,
current_user: assigns.current_user,
chat: assigns.chat,
message: assigns.messages |> Enum.find(&(&1.id == assigns.id)),
})
{:ok, socket}
end
def mount(socket) do
if connected?(socket) do
# This part doesn't work, as there's no `:id` in assigns
MyAppWeb.Endpoint.subscribe("messages:#{socket.assigns.id}")
end
{:ok, socket}
end
end
My questions are:
- How can I access the
:id
in the component’smount
call? - Will this be a more efficient way to do this? Since my messages are “rich messages” i.e. more than just displayed text, but they have their own events (likes, replies, etc.) that need to be listened to, is it actually more efficient to handle this state in a separate component, rather than handling all the chat and messages state in the main LiveView module?
Thanks!