Hello there.
I have been trying out liveview for some time, but the diff tracking is still kind of a mystery to me. I’m running into a weird issue when combining it with pub/sub.
I checked out this repo(which is not mine) which creates pretty basic comment functionality with liveview: https://github.com/snewcomer/live-comment
There is one liveview with all the comments. Each comment is a live component, possibly containing children comments. So we have recursive comment component(show.ex). When I post a child comment, assigns change in the specific component and the component is rerendered.
def handle_event(“save”, %{“comment” => comment_params}, socket) do
comment_params
|> Map.put(“parent_id”, socket.assigns.id)
|> Managed.create_comment()
|> case do
{:ok, new_comment} →
{:noreply, assign(socket, form_visible: false, children: [new_comment])}{:error, %Ecto.Changeset{} = changeset} →
{:noreply, assign(socket, changeset: changeset)}
end
end
This works as expected.
Since we are using temporary assigns and phx-udpate append, only the new comment is send over the wire.
The trouble begins when we broadcast this new comment to all liveviews using Phoenix.PubSub.broadcast_from!
The liveview is subscribed to new_comment event and when it comes, it calls send_update with the comment component id like this:
def handle_info({Managed, :new_comment, comment}, socket) do
if comment.parent_id do
send_update(CommentLive.Show, id: comment.parent_id, children: [comment])
{:noreply, socket}
else
{:noreply, assign(socket, comments: [comment])}
end
end
Actual behaviour:
The incognito window shows that all siblings are sent over to the client. Note: not ALL comments are sent. the other root comments are not sent. only the children belonging to same parent. So if I have comments like this:
root1
comm1
comm2
root2
root3
and I add comm3 as a reply to root1, all children of root1 are sent to the client(comm1, comm2 and the new comm3). root2 and root3 are not sent at all.
Expected behaviour(for me)
:new_comment event is published, the liveview in incognito window is subscribed, gets the new child comment, calls send_update with the comment. Then the corresponding livecomponent updated its assigns with the new comment and only the new comment is sent as diff to the client(just as it works without pub/sub)
So from the previous example, only the comm3(without comm1 and comm2) should be sent to the client.
My question is why are all the siblings sent to the client, when I create new comment?
Is this supposed to work as I’m expecting and I’m just doing something wrong, or is this not the way it works and my understanding is wrong?
thanks