I do believe that improving list comprehensions is worth exploring, but I think one solution for optimizing payload sizes wasn’t really discussed here (apart from being briefly mentioned in José last message): LiveComponents
If the only goal is to optimize payload size, ignoring memory usage, LiveComponents can be part of the solution. Re-visiting the original demo with LiveComponents:
Mix.install([{:phoenix_playground, "~> 0.1.3"}])
defmodule ListItem do
use Phoenix.LiveComponent
def render(assigns) do
~H"""
<li><%= @item.name %></li>
"""
end
end
defmodule DemoLive do
use Phoenix.LiveView
def render(assigns) do
~H"""
<button phx-click="add">add</button>
<ul>
<.live_component :for={i <- @items} id={i.id} item={i} module={ListItem} />
</ul>
"""
end
def mount(_params, _session, socket) do
{:ok, assign(socket, :items, [])}
end
def handle_event("add", _params, socket) do
items = socket.assigns.items
id = length(items)
new_item = %{id: id + 1, name: "New#{id + 1}"}
{:noreply, assign(socket, :items, [new_item | items])}
end
end
PhoenixPlayground.start(live: DemoLive)
The payload size still increases with each item, but only the component id is sent.
This can be further improved with streams:
Mix.install([{:phoenix_playground, "~> 0.1.3"}])
defmodule ListItem do
use Phoenix.LiveComponent
def render(assigns) do
~H"""
<li id={@id}><%= @item.name %></li>
"""
end
end
defmodule DemoLive do
use Phoenix.LiveView
def render(assigns) do
~H"""
<button phx-click="add">add</button>
<ul id="items" phx-update="stream">
<.live_component :for={{id, item} <- @streams.items} id={id} item={item} module={ListItem} />
</ul>
"""
end
def mount(_params, _session, socket) do
{:ok, socket |> assign(:count, 0) |> stream(:items, [])}
end
def handle_event("add", _params, socket) do
id = socket.assigns.count
new_item = %{id: id, name: "New#{id + 1}"}
{:noreply, socket |> stream_insert(:items, new_item) |> update(:count, &(&1 + 1))}
end
end
PhoenixPlayground.start(live: DemoLive)
to have a basically constant diff size.
Of course the UX is not optimal, because one has to define a new module, but maybe this is also something that could be improved, e.g., by having “inline live components”?