LiveView function component diffing and static content

I am upgrading a project to liveview 0.17 and playing around with factoring into components. In simplified form I have a LV that renders a list of items and then later sees updates to those items:

defmodule AppWeb.PageLive do
  use AppWeb, :live_view

  @impl true
  def mount(_params, _session, socket) do
    Process.send_after(self(), :tick, 5_000)
    {:ok, assign(socket, items: [{1, :foo}, {2, :foo}])}
  end

  def handle_info(:tick, socket) do
    {:noreply, assign(socket, items: [{1, :bar}, {2, :bar}])}
  end

  def render(assigns) do
    ~H"""
    <%= for {item, _} <- @items do %>
      <div><%= item %></div>
    <% end %>
    """
  end
end

After 5 seconds I get the expected update over the socket which looks like:

["4",null,"lv:phx-FrB9AuJw0Qh3WgFk","diff",{"2":{"0":{"d":[["1"],["2"]]}}}]

Iā€™d like to extract the item contents into a component, so I have

  defmodule Item do
    use Phoenix.Component
    def item(assigns) do
      ~H"""
      <div><%= @item %></div>
      """
    end
  end

and replace the contents of the for comprehension with <Item.item item={item}/>. Now the update message is different and longer:

["4",null,"lv:phx-FrB9C1CrSUjYlQJi","diff",{"2":{"0":{"d":[[{"0":"1","s":["<div>","</div>"]}],[{"0":"2","s":["<div>","</div>"]}]]}}}]

That is, along with diffs for dynamic content is a "s" key of the payload that contains a copy of static fragments of the component for each item. Is there a way to avoid this that I have missed? In the real version the static content is much bigger than the dynamic content so the messages become much longer after the refactor.

1 Like

Not right now but I will optimize it in master. So it should be better in future releases. If not, I will let you know!

4 Likes

Pushed. Please try master and let me know.

2 Likes

Awesome thanks for looking at this so quickly.

On master the update messages now look like

["4",null,"lv:phx-FrC-PpvAIkBLtAek","diff",{"2":{"0":{"d":[[{"0":"1","s":0}],[{"0":"2","s":0}]],"p":{"0":["<div>","</div>"]}}}}]

The static parts are de-duped per message which is a big improvement! I would note though that sending the template statics on every update is still a penalty wrt the non-component version ā€“ in my real use case the messages still end up being mostly statics.

Maybe there is some further opportunity to do either in-lining of components during compile, or perhaps cache the fact that we have sent a particular template so it only needs to be sent once, or something else fancy.

Thanks again!

Correct. BUT master works recursively while before it was only the portion immediately inside the comprehension. :slight_smile: