@@ -37,9 +37,8 @@ part if it changes.
3737
3838The tracking of changes is done via assigns. If the ` @title ` assign
3939changes, then LiveView will execute the dynamic parts of the template,
40- ` expand_title(@title) ` , and send
41- the new content. If ` @title ` is the same, nothing is executed and
42- nothing is sent.
40+ ` expand_title(@title) ` , and send the new content. If ` @title ` is the same,
41+ nothing is executed and nothing is sent.
4342
4443Change tracking also works when accessing map/struct fields.
4544Take this template:
@@ -87,7 +86,7 @@ Generally speaking, **data loading should never happen inside the template**,
8786regardless if you are using LiveView or not. The difference is that LiveView
8887enforces this best practice.
8988
90- ## Pitfalls
89+ ## Common pitfalls
9190
9291There are some common pitfalls to keep in mind when using the ` ~H ` sigil
9392or ` .heex ` templates inside LiveViews.
@@ -149,8 +148,9 @@ The same functions can be used inside function components too:
149148
150149Generally speaking, avoid accessing variables inside ` HEEx ` templates, as code that
151150access variables is always executed on every render. The exception are variables
152- introduced by Elixir's block constructs. For example, accessing the ` post ` variable
153- defined by the comprehension below works as expected:
151+ introduced by Elixir's block constructs, such as ` if ` and ` for ` comprehensions.
152+ For example, accessing the ` post ` variable defined by the comprehension below
153+ works as expected:
154154
155155``` heex
156156<%= for post <- @posts do %>
@@ -238,6 +238,55 @@ is passed to each child component, only re-rendering what is necessary.
238238However, generally speaking, it is best to avoid passing ` assigns ` altogether
239239and instead let LiveView figure out the best way to track changes.
240240
241+ ### Comprehensions
242+
243+ HEEx supports comprehensions in templates, which is a way to traverse lists
244+ and collections. For example:
245+
246+ ``` heex
247+ <%= for post <- @posts do %>
248+ <section>
249+ <h1>{expand_title(post.title)}</h1>
250+ </section>
251+ <% end %>
252+ ```
253+
254+ Or using the special ` :for ` attribute:
255+
256+ ``` heex
257+ <section :for={post <- @posts>}>
258+ <h1>{expand_title(post.title)}</h1>
259+ </section>
260+ ```
261+
262+ Comprehensions in templates are optimized so the static parts of
263+ a comprehension are only set once, regardless of the number of items.
264+ However, keep in mind LiveView does not track changes within the
265+ collection given to the comprehension. In other words, if one entry
266+ in ` @posts ` changes, all posts are sent again.
267+
268+ There are two common solutions to this problem.
269+
270+ The first one is to use ` Phoenix.LiveComponent ` for each item in the
271+ comprehension:
272+
273+ ``` heex
274+ <section :for={post <- @posts>}>
275+ <.live_component module={PostComponent} id={"post-#{post.id}"} post={post} />
276+ </section>
277+ ```
278+
279+ Since LiveComponents have their own assigns, LiveComponents would allow
280+ you to perform change tracking for each item. If the ` @posts ` variable
281+ changes, the client will simply send a list of component IDs (which are
282+ integers) and only the data for the posts that actually changed.
283+
284+ Another solution is to use ` Phoenix.LiveView.stream/4 ` , which gives you
285+ precise control over how elements are added, removed, and updated. Streams
286+ are particularly useful when you don't need to keep the collection in memory,
287+ allowing you to reduce the data sent over the wire and the server memory
288+ usage.
289+
241290### Summary
242291
243292To sum up:
0 commit comments