<turbo-stream action="append" target="posts_list"><template>    <div class="postbit" id="335731" data-post-id="335731">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="steffend" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/steffend/120/20548_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  steffend
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Phoenix Core Team</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>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</p>
<p>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:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">Mix.install([{:phoenix_playground, "~&gt; 0.1.3"}])

defmodule ListItem do
  use Phoenix.LiveComponent

  def render(assigns) do
    ~H"""
    &lt;li&gt;&lt;%= @item.name %&gt;&lt;/li&gt;
    """
  end
end

defmodule DemoLive do
  use Phoenix.LiveView

  def render(assigns) do
    ~H"""
    &lt;button phx-click="add"&gt;add&lt;/button&gt;

    &lt;ul&gt;
      &lt;.live_component :for={i &lt;- @items} id={i.id} item={i} module={ListItem} /&gt;
    &lt;/ul&gt;
    """
  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)
</code></pre>
<p>The payload size still increases with each item, but only the component id is sent.</p>
<p>This can be further improved with streams:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">Mix.install([{:phoenix_playground, "~&gt; 0.1.3"}])

defmodule ListItem do
  use Phoenix.LiveComponent

  def render(assigns) do
    ~H"""
    &lt;li id={@id}&gt;&lt;%= @item.name %&gt;&lt;/li&gt;
    """
  end
end

defmodule DemoLive do
  use Phoenix.LiveView

  def render(assigns) do
    ~H"""
    &lt;button phx-click="add"&gt;add&lt;/button&gt;

    &lt;ul id="items" phx-update="stream"&gt;
      &lt;.live_component :for={{id, item} &lt;- @streams.items} id={id} item={item} module={ListItem} /&gt;
    &lt;/ul&gt;
    """
  end

  def mount(_params, _session, socket) do
    {:ok, socket |&gt; assign(:count, 0) |&gt; stream(:items, [])}
  end

  def handle_event("add", _params, socket) do
    id = socket.assigns.count
    new_item = %{id: id, name: "New#{id + 1}"}
    {:noreply, socket |&gt; stream_insert(:items, new_item) |&gt; update(:count, &amp;(&amp;1 + 1))}
  end
end

PhoenixPlayground.start(live: DemoLive)
</code></pre>
<p>to have a basically constant diff size.</p>
<p>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”?</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="335731" data-batch-url="/posts/batch_likers">
                        5
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/possible-payload-size-improvement-to-heex-list-comprehensions/64986/22">Post #21</a>
	                </div>
	            </div>
              <div id="likers-container-335731" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="335731"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #21"></div>
  </section>
</div>
    <div class="postbit" id="335743" data-post-id="335743">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="josevalim" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/josevalim/120/1787_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  josevalim
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Creator of Elixir</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>We could trivially add inline live components by having a function component that calls the LiveComponent passing an inner block as argument and rendering it inside the component? We only need an ID for the component. Perhaps that’s the simplest solution to the problem at hand?</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="335743" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/possible-payload-size-improvement-to-heex-list-comprehensions/64986/23">Post #22</a>
	                </div>
	            </div>
              <div id="likers-container-335743" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="335743"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #22"></div>
  </section>
</div>
    <div class="postbit" id="335758" data-post-id="335758">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="josevalim" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/josevalim/120/1787_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  josevalim
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Creator of Elixir</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Here is an iteration on top of yours <a class="mention" href="/u/steffend" rel="nofollow">@steffend</a>:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">Mix.install([{:phoenix_playground, "~&gt; 0.1.3"}])

defmodule CachedComponent do
  use Phoenix.LiveComponent

  def cached_component(assigns) do
    ~H"""
    &lt;.live_component module={CachedComponent} id={assigns.id} inner_block={assigns.inner_block} /&gt;
    """
  end

  def render(assigns) do
    rendered = ~H"""
    &lt;%= render_slot(@inner_block, []) %&gt;
    """

    # This is a hack
   %{rendered | root: true}
  end
end

defmodule DemoLive do
  use Phoenix.LiveView
  import CachedComponent, only: [cached_component: 1]

  def render(assigns) do
    ~H"""
    &lt;button phx-click="add"&gt;add&lt;/button&gt;

    &lt;ul id="items" phx-update="stream"&gt;
      &lt;.cached_component :for={{id, item} &lt;- @streams.items} id={id}&gt;
        &lt;li id={id}&gt;&lt;%= item.name %&gt;&lt;/li&gt;
      &lt;/.cached_component&gt;
    &lt;/ul&gt;
    """
  end

  def mount(_params, _session, socket) do
    {:ok, socket |&gt; assign(:count, 0) |&gt; stream(:items, [])}
  end

  def handle_event("add", _params, socket) do
    id = socket.assigns.count
    new_item = %{id: id, name: "New#{id + 1}"}
    {:noreply, socket |&gt; stream_insert(:items, new_item) |&gt; update(:count, &amp;(&amp;1 + 1))}
  end
end

PhoenixPlayground.start(live: DemoLive)
</code></pre>
<p>There is a hack in there, which we can ignore for now. It also has one limitation in that, although we now diff the list, we don’t diff inside the list elements. However, now that I look at the problem, I don’t think any of the solutions discussed so far would be able to address this (except proper LiveComponents).</p>
<p>We could add the API above to Phoenix itself, here are some options:</p>
<ol>
<li>
<p>Introduce “anonymous LiveComponents”, which is a LiveComponent where its rendering block is given and there is no module, so we could do:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">  &lt;.live_component :for={{id, item} &lt;- @streams.items} id={id}&gt;
    &lt;li id={id}&gt;&lt;%= item.name %&gt;&lt;/li&gt;
  &lt;/.live_component&gt;
</code></pre>
<p>Making this work requires changes to the engine, so we validate the root (as we do for LiveComponents).</p>
</li>
<li>
<p>Introduce some sort <code>cache_tag</code>, which mirrors <code>dynamic_tag</code>,  so we could do:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">  &lt;.cache_tag :for={{id, item} &lt;- @streams.items} tag_name="li" id={id}&gt;
    &lt;%= item.name %&gt;
  &lt;/.cache_tag&gt;
</code></pre>
<p>I don’t like the name <code>cache_tag</code>, since this is really only about comprehensions, but that’s the overall idea. Other names could be introduced.</p>
</li>
</ol> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="335758" data-batch-url="/posts/batch_likers">
                        4
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/possible-payload-size-improvement-to-heex-list-comprehensions/64986/24">Post #23</a>
	                </div>
	            </div>
              <div id="likers-container-335758" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="335758"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #23"></div>
  </section>
</div>
    <div class="postbit" id="335762" data-post-id="335762">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="shahryarjb" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/shahryarjb/120/39485_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  shahryarjb
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote group-livebook_core_team" data-username="josevalim" data-post="24" data-topic="64986">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/josevalim/48/1787_2.png" class="avatar"> josevalim:</div>
<blockquote>
<p>Introduce “anonymous LiveComponents”, which is a LiveComponent where its rendering block is given and there is no module, so we could do:</p>
</blockquote>
</aside>
<p>Wow <code>anonymous LiveComponents</code> is very cool idea <img src="https://forum.elixirforum.com/images/emoji/apple/light_bulb.png?v=15" title=":light_bulb:" class="emoji" alt=":light_bulb:" loading="lazy" width="20" height="20"> and I think the <code>anonymous LiveComponents</code> can accepts <code>cache_tag</code> as list params</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="335762" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/possible-payload-size-improvement-to-heex-list-comprehensions/64986/25">Post #24</a>
	                </div>
	            </div>
              <div id="likers-container-335762" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="335762"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #24"></div>
  </section>
</div>
    <div class="postbit" id="335837" data-post-id="335837">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="Jskalc" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/Jskalc/120/35876_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  Jskalc
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Personally I don’t like the idea to push people towards LiveComponents just to have better performance. I’ve been there, done that, but it didn’t felt “right”.</p>
<p>LiveComponents have their own lifecycle and state. They can handle events, update state and re-render. This usage basically stripes them down to… being a marker in HEEX?</p>
<p>If I’m correct it’s working because it persists all the used live component IDs and when we render more it can diff these ids to know which should be added / updated, at the expense of some memory for keeping these IDs. Just, there’s more chatting (I’ve noticed client sends updates about no-longer used IDs so they can be cleaned up?) and you need to use them with streams otherwise there is no performance or memory gain (correct?)</p>
<p>I think I came up with a good example showing what I’d love to have.</p>
<ul>
<li>It’s a 10-element list comprehension</li>
<li>on click, these 10 elements are generated again out of 11 possible elements, so there’s one insertion, one removal and 9 updates</li>
<li>there’s one shared assign used in all these elements</li>
</ul>
<pre data-code-wrap="elixir"><code class="lang-elixir">Mix.install([{:phoenix_playground, "~&gt; 0.1.3"}])

defmodule DemoLive do
  use Phoenix.LiveView

  def render(assigns) do
    ~H"""
    &lt;button phx-click="randomize"&gt;randomize&lt;/button&gt;

    &lt;ul&gt;
      &lt;li :for={item &lt;- @items}&gt;
        Count: &lt;span&gt;&lt;%= @count %&gt;&lt;/span&gt;, 
        item: &lt;%= item.name %&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
    """
  end

  def mount(_params, _session, socket) do
    socket = socket |&gt; assign(:count, 0) |&gt; assign(:items, random_items())
    {:ok, assign(socket, :count, 0)}
  end

  def handle_event("randomize", _params, socket) do
    {:noreply, socket |&gt; assign(:items, random_items()) |&gt; update(:count, &amp;(&amp;1 + 1))}
  end

  def random_items() do
    1..11
    |&gt; Enum.take_random(10)
    |&gt; Enum.map(&amp;%{id: &amp;1, name: "New#{&amp;1 + 1}"})
  end
end

PhoenixPlayground.start(live: DemoLive)
</code></pre>
<p>I believe the smallest diff would contain:</p>
<ul>
<li>reorder by sending order of IDs</li>
<li>9 updates to the shared assign <code>@count</code></li>
<li>1 full insert</li>
</ul>
<p>At the same time, it would be best to make it working with small changes to the non-optimized code. I’ve tested it with <code>.cached_component</code> and it didn’t help. Maybe it would be better with <code>stream_diff</code> but probably it would break that shared assign part, since we wouldn’t update it for non-touched elements. A bit tricky, mostly because in the previous part of the discussion we ignored assigns coming outside of the current item <img src="https://forum.elixirforum.com/images/emoji/apple/thinking.png?v=15" title=":thinking:" class="emoji" alt=":thinking:" loading="lazy" width="20" height="20"></p>
<p>What do you think?</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="335837" data-batch-url="/posts/batch_likers">
                        2
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/possible-payload-size-improvement-to-heex-list-comprehensions/64986/26">Post #25</a>
	                </div>
	            </div>
              <div id="likers-container-335837" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="335837"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #25"></div>
  </section>
</div>
    <div class="postbit" id="335854" data-post-id="335854">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="Schultzer" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/Schultzer/120/4339_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  Schultzer
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Yeah, I’m not sold on LiveComponents, I’ve completely avoided them in my app, I know that processes are cheap, but I don’t think thats a good argument alone, especially if we can avoid building chatty apps.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="335854" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/possible-payload-size-improvement-to-heex-list-comprehensions/64986/27">Post #26</a>
	                </div>
	            </div>
              <div id="likers-container-335854" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="335854"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #26"></div>
  </section>
</div>
    <div class="postbit" id="335855" data-post-id="335855">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="LostKobrakai" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/LostKobrakai/120/3072_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  LostKobrakai
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>LiveComponents don’t use additional processes. They run within their parents LV process.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="335855" data-batch-url="/posts/batch_likers">
                        3
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/possible-payload-size-improvement-to-heex-list-comprehensions/64986/28">Post #27</a>
	                </div>
	            </div>
              <div id="likers-container-335855" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="335855"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #27"></div>
  </section>
</div>
    <div class="postbit" id="335856" data-post-id="335856">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="josevalim" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/josevalim/120/1787_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  josevalim
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Creator of Elixir</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="Jskalc" data-post="26" data-topic="64986">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/jskalc/48/35876_2.png" class="avatar"> Jskalc:</div>
<blockquote>
<p>Personally I don’t like the idea to push people towards LiveComponents just to have better performance. I’ve been there, done that, but it didn’t felt “right”.</p>
</blockquote>
</aside>
<p>I agree and disagree. Nothing is perfect. If LiveComponents are the best solution to the problem right now, then that’s what we should push people to. However, we are discussing ways to improve the current status quo, so let’s consider that indeed they can be improved.</p>
<p>Now we should split the discussion in two. Do LiveComponents provide <em>technically</em> (not API wise) the benefits we want? And I think the answer is yes. If you use a list (it does not have to be streams) in your example above and you put each item inside a LiveComponent, adding, removing, updating, and re-ordering should send minimal diffs. If this is indeed true, then it is great news! It means we have already solved the problem, we now only need to improve the API surface. Can you verify if this is true?</p>
<p>Once we verify this, then it is a question of how to better encapsulate LiveComponents so they are less bureaucratic (for example, they don’t require a whole module).</p>
<p>For example, we could say we could cache any function component as long as it has an <code>:id</code> (or <code>:cache</code> or whatever) directive. So your template could be written as:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">  def render(assigns) do
    ~H"""
    &lt;button phx-click="randomize"&gt;randomize&lt;/button&gt;

    &lt;ul&gt;
      &lt;%= for item &lt;- @items do %&gt;
        &lt;.list_item :id={item.id} count={@count} item={@item} /&gt;
      &lt;% end %&gt;
    &lt;/ul&gt;
    """
  end

  defp list_item(assigns) do
    ~H"""
    &lt;li id={@id}&gt;
      Count: &lt;span&gt;&lt;%= @count %&gt;&lt;/span&gt;, 
      item: &lt;%= @item.name %&gt;
    &lt;/li&gt;
    """
  end
</code></pre>
<p>The reason why we need at least a function component is so we can track its own <code>assigns</code> with its own changed entries. And asking people to write a function component to rely on this optimization should be more straight-forward than whole LiveComponents (or even streams).</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="335856" data-batch-url="/posts/batch_likers">
                        2
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/possible-payload-size-improvement-to-heex-list-comprehensions/64986/29">Post #28</a>
	                </div>
	            </div>
              <div id="likers-container-335856" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="335856"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #28"></div>
  </section>
</div>
    <div class="postbit" id="335867" data-post-id="335867">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="Schultzer" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/Schultzer/120/4339_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  Schultzer
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>TIL, that’s awesome, I was of the believe that was the difference with function components vs live components. I’ll take another look at this.</p>
<p>I guess where there is a difference is that you need to send_updates over the channel, vs just assigning and render. So a message will still need to be send with <a href="https://hexdocs.pm/phoenix_live_view/1.0.0-rc.6/Phoenix.LiveView.html#send_update/3" class="inline-onebox" rel="noopener nofollow ugc">Phoenix.LiveView — Phoenix LiveView v1.0.0-rc.6</a> this does make your app more chatty especially if you broadcast to live_views and have to use send_update within them!</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="335867" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/possible-payload-size-improvement-to-heex-list-comprehensions/64986/30">Post #29</a>
	                </div>
	            </div>
              <div id="likers-container-335867" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="335867"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #29"></div>
  </section>
</div>
    <div class="postbit" id="335871" data-post-id="335871">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="josevalim" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/josevalim/120/1787_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  josevalim
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Creator of Elixir</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>The update is sending a message to the current process, which is very cheap. It doesn’t go over any channel.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="335871" data-batch-url="/posts/batch_likers">
                        2
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/possible-payload-size-improvement-to-heex-list-comprehensions/64986/31">Post #30</a>
	                </div>
	            </div>
              <div id="likers-container-335871" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="335871"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #30"></div>
  </section>
</div>
</template></turbo-stream><turbo-stream action="replace" target="load-more-container"><template><div id="load-more-container" class="load-more-container">
    <a class="load-more-button" data-turbo-stream="true" href="/topics/64986/load_more?page=4">Load more posts (20 remaining)</a>
</div></template></turbo-stream>