I have a LiveComponent that builds a <table> from a map.
Everything worked fine until I removed an IO.inspect from the beginning of the heredoc.
Now I don’t get updates (the first time the component is rendered, but not when its changed). If I put the inspect back in everything works…
~L"""
<% IO.inspect m %> <---- when I take this away: no more updates
<%= for {_k, v} <- m do %>
<%= inspect v %>
<% end %>
"""
Putting the thing into the assigns would take away work from the component that belongs there.
It seems like if I do anything else with the map (like <%= m.field %>) inside the table it works. If I only access the map in the loop, there are no updates.
Is get_info a pure function? I mean, did id or things change?
It is a good discipline to make sure there is nothing but pure functions in the rendering.
yes, the function is pure, the only odd thing I’m doing is, that the maps i grab ID from are not directly in the assings but in another map (state). Here is the full code of the component (omitting the heredoc)
def render(%{selected_param: selected_param, state: state} = assigns) do
{ref, type} = get_param_info(selected_param, state)
...
def get_param_info(
ref_id,
%{
parameter_refs: parameter_refs,
parameter_types: parameter_types
}
) do
ref = Map.get(parameter_refs, ref_id)
type = Map.get(parameter_types, Map.get(ref, :parameterType))
{ref, type}
end
It seems like what you’re doing is explicitly warned against in the documentation: Live EEx Pitfalls
Similarly, do not define variables at the top of your render function:
…
Instead explicitly precompute the assign in your LiveView, outside of render:
…
# the calling leex
<%= live_component @socket, MyComponent,
info: MyComponent.get_info(@display_this, @things)
...
# MyComponent.ex
def render(%{info: {m, related_thing}} = assigns) do
...
~L"""
<% IO.inspect m %> <---- when I take this away: no more updates
<%= for {_k, v} <- m do %>
<%= inspect v %>
<% end %>
"""
for now I’ve added
<div style="display: none">
<%= inspect m %>
</div>
which does not hurt right now, but I’d really like to understand whats going on.
Also if I understand liveeex-pitfalls correctly, these things should only lead to inefficent change detection, not to complete failure to render an update.
Without wanting to take anything out of context I understand
LiveView has to disable change tracking whenever variables are used in the template
…
Generally speaking, avoid accessing variables inside LiveViews, as code that access variables is always executed on every render.
so that performance will be bad, but nothing will break.
with the exception of variables introduced by Elixir basic case, for, and other block constructs
Would the with construct be included in this set? I understand the with do-end block limits the scope of the temporary variables. Would something like this be ok?
<%= with x <- calculated_variable() do %>
... use x here
<% end %>