Why is LiveView sending all of this un-changed data

LiveView does not perform diffing inside lists. Therefore, if you change one item in the list, from LiveView’s view the whole list is changed and therefore the for is evaluated again. The recommended approach to handle this is streams, which also have the advantage of not taking up memory on the server.

There is another way to do it, if you need to keep state on the server: LiveComponents. If you refactor the list items to be rendered in their own LiveComponents, the diff will be minimized as well:

defmodule TestLiveViewUpdatesWeb.ListComponent do
  use TestLiveViewUpdatesWeb, :live_component

  def render(assigns) do
    ~H"""
    <li><%= @element %></li>
    """
  end
end

defmodule TestLiveViewUpdatesWeb.HomeLive do
  use TestLiveViewUpdatesWeb, :live_view

  def mount(_params, _session, socket) do
    {:ok,
     socket
     |> assign(
       elements: ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"]
     )}
  end

  def render(assigns) do
    ~H"""
    <div>
      <ul>
        <.live_component id={element} module={TestLiveViewUpdatesWeb.ListComponent} :for={element <- @elements} element={element} />
      </ul>
      <br /><br />
      <button phx-click="change_four">Change Four</button>
    </div>
    """
  end

  def handle_event("change_four", _params, socket) do
    elements = List.replace_at(socket.assigns.elements, 3, "#{:rand.uniform(1000)}")
    {:noreply, assign(socket, elements: elements)}
  end
end
2 Likes