I’m looking for some good practices or rules of thumb on when to go for stateless LiveComponent
s vs regular functions.
I know that LiveView is rather new, so the goal of this post to get some great discussion (similiar to what was posted in LiveView with complex layouts ). I feel these discussions can help shape the practices around LiveView.
This is part of the docs (Phoenix.LiveComponent — Phoenix LiveView v0.20.2) triggered me:
You should also avoid using components to provide abstract DOM components. As a guideline, a good LiveComponent encapsulates application concerns and not DOM functionality. For example, if you have a page that shows products for sale, you can encapsulate the rendering of each of those products in a component. This component may have many buttons and events within it. On the opposite side, do not write a component that is simply encapsulating generic DOM components.
If I’m reading this right, this is saying that you should use function for abstractions that are not part of your application, like a styled button or badge.
I can see why that first part would be a good guideline, what I don’t see is when you should go for a LiveComponent
then. Why pick a component instead of function (maybe a function in a module) to
encapsulate your application concerns. What is the advantage?
defmodule ProductComponent do
use Phoenix.LiveComponent
def render(assigns) do
~L"""
"""
end
end
defmodule ProductModule do
def custom_render(price, title, description) do
assigns = %{price: price, title: title, description: description}
~L"""
"""
end
end
Why would you choose ProductComponent
over ProductModule
?
I cannot think about any good reasons so far, but then I read this (Feature suggestion: phx-update="list" · Issue #1214 · phoenixframework/phoenix_live_view · GitHub) by @josevalim
Something else you could do and it should speed up things today is to continue rendering it as a list but render each list entry as a component. The components are tracked individually which means re-rendering the list is fast (we only send the component IDs).
So this means that picking components over functions could result in performance improvements. But that was not something I was expecting. On the other hand, it seems like it’s the exact opposite of the original guideline (don’t use components to abstract DOM functionality). Here I would have picked a function to render list items for the exact reason of not abstracting DOM functionality, but it would result in slower performance.
Lastely one related question to the above.
From the same docs:
Therefore it is your responsibility to keep only the assigns necessary
in each component. For example, avoid passing all of LiveView components
when rendering a component:
<%= live_component @socket, MyComponent, assigns %>
Instead pass only the keys that you need:
<%= live_component @socket, MyComponent, user: @user, org: @org %>
Luckily, because LiveViews and LiveComponents are in the same process,
they share the same data structures. For example, in the code above,
the view and the component will share the same copies of the@user
and@org
assigns.
but if the components share the data structures, then what is the difference between passing all assigns and just some of them?