I have an application that renders hundreds of individual entities, and occasionally updates a few of them based on user interaction. I’m having a very hard time getting LiveView to only send the data for those entities that have changed. I’ve boiled down what I don’t understand to this very minimal example.
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>
<li :for={element <- @elements}><%= element %></li>
</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
This code renders the list elements, and when the user clicks the button it updates just the “four” to a random number. When I look in the message that is sent when I click the button, I see this.
It re-sends the values for all the elements, not just the fourth. I was under the impression that LiveView would send only what has changed. What am I not understanding here? Is there some way I can change the code to recognize that the other elements of the list have not changed, and not send them over the network?
In my larger app this results in 200kb being sent over the wire, when just a few bytes could represent what has changed.