(ab)Using closures with heex components?

Is there any technical reason not to do this, specifically around change tracking in live views?

def my_component(assigns) do
  value = assigns.something <> assigns.something_else
  # never calling assigns = assign(assigns, :value, value)
  ~H"""
     <div><%= value %></div> <!-- not using @value -->
   """
end

My specific usecase is

def my_component(assigns) do
  ~H"""
     <div>
       <%= if assigns[:label] %> <!-- accessing `assigns` -->
         <%= render_slot @label %>
       <% else %>
         <%= humanize(@field) %>
       <% end %>
     </div>
   """
end

vs

def my_component(assigns) do
  # always go through an @var
  assigns = assign_new(assigns, :label, fn -> false end)
  ~H"""
     <div>
       <%= if @label %>
         <%= render_slot @label %>
       <% else %>
         <%= humanize(@field) %>
       <% end %>
     </div>
   """
end

I would generally preference using assign() explicitly, but I am wondering if I am adding verbosity when there is no point.

Is assigns[:label] as good as @label (or even label if in scope), in terms of change tracking and live view “health”?

see here: Assigns and HEEx templates - pitfalls

1 Like

Ah yes, perfect.

Similarly, do not define variables at the top of your render function:

def render(assigns) do
  sum = assigns.x + assigns.y

  ~H"""
  <%= sum %>
  """
end

Instead explicitly precompute the assign in your LiveView, outside of render:

assign(socket, sum: socket.assigns.x + socket.assigns.y)

E: Though that is technically about LiveViews, not functional components.

It’s about heex, so it applies to functional components as well.

Also note, that your code may work, until it won’t.

2 Likes

Yeah that’s

Aren’t we suppost to just let it crash? :slight_smile:

Yeah that’s what I figured which is why I’d been preferencing the explicit assign() but wasn’t sure if I was just being overly cautious.