(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”?

1 Like

see here: Assigns and HEEx templates - pitfalls

2 Likes

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.

1 Like

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

1 Like

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

3 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.

1 Like

What about this example though?

  def greet(assigns) do
    ~H"""
    <p>Hello, <%= assigns.name %></p>
    """
  end

https://hexdocs.pm/phoenix_live_view/Phoenix.Component.html

Here assigns is accessed directly. But I thought bindings should only be accessed via @.

I currently have code like this, do I rewrite it?

<.form_field {form_field_assigns(assigns)}><.text_input {input_assigns(assigns)} /></.form_field>
2 Likes