coen.bakker

coen.bakker

When to use a live component, instead of a functional component?

Alex Korban recently wrote an article called “Thoughts on Elixir, Phoenix and LiveView after 18 months of commercial use”, where he mentions that he avoids using live components whenever possible.

Live components are best avoided if possible, in my view.

There is a discussion of his article on Hacker News. Here Jose Valim agrees with him on his point about live components.

You are 100% correct on functional components vs live components. I will make it clearer in the docs the former should be preferred

The live component docs indeed include a short section about when to use functional components or live components.

Generally speaking, you should prefer functional components over live components, as they are a simpler abstraction, with a smaller surface area. The use case for live components only arises when there is a need for encapsulating both event handling and additional state.

However, I still don’t fully understand the rational behind choosing the one or the other.

For example, what does it mean for something to have a smaller surface area, in the context? And why is smaller better?

And why should live components exclusively be used when there is a need for event handling AND additional state?

What are the (hidden) costs of using live components, that make them something to avoid?

One reason I have been used live components is to make my code simpler to understand and easier to reason about, by encapsulation event handling and state. However, in some cases my code did not improve as much as I expected in that regard, partly because of the extra message handling between the root live view and the live component.

Most Liked

w0rd-driven

w0rd-driven

Where things splinter is when you want to use PubSub. That relies on handle_info callbacks, which are so far only available close to the process or LiveView.

For a simple count badge, it was easier for me to use a functional component the LiveView handled state for. It ended up being 3 separate counts but I had less mental load with less oddities. My mental model for a badge counter is to init the record count from the database then use PubSub to increment that count.

I had problems understanding how to do that with update of LiveComponent in the mix. I wanted the state of each count with the component because colocating that state made sense. Marshalling messages through handle_info made less sense to me but I may be missing the plot on that.

I would say there is a place for a cheatsheet, checklist, or flow chart diagram that’s like “If you want PubSub, you try X with Y.”

cmo

cmo

I have this SQL query builder component. At some point I wanted to use it on a couple of other pages. It uses url query params and all the events were handled in the liveview. I went with keeping it as a function component and adding the params and event handling to the parent liveviews with attach_hook. This kept all the behavior in a module and there is only one callback to implement in the module that uses it.

Pretty sure I looked into doing it as a live component but as you said, you end up having to send events back and forth and it can get out of hand for some use cases. It is especially pointless when there is no internal state or events.

Say you’ve got a calendar component. It can be in either day, week or month view, has to accept events for navigating back and forwards through time. Most of the events and state are internal. The parent only cares about the date picked. This can be a live component and the parent handles one event and passes one assign. The rest are internal. You’re unlikely to have more than one or two on a page so the overhead isn’t much of a worry.

coen.bakker

coen.bakker

This is helping me thinking about code organization better. I found an example in the codebase of LiveBook of this approach (see the LivebookWeb.Confirm module). Potentially a game changer for me personally. I did not realize the full power of hooks

Last Post!

rhcarvalho

rhcarvalho

I think not, just spelling. Function/functional components are functions that take a single argument assigns map and return a HEEx template:

def my_component(assigns) do
  ~H"""
  <h1>hello</h1>
  """
end

The latter. The former is not possible, as those are only functions. But events (in a LiveView or LiveComponent module) can mutate the assigns and change tracking will take care of updating whatever state changed in the function component, send the diff to the client and patch the DOM.

The emphasis on both is to guide people not to overreach to a more complicated solution. LCs have their space for organizing “too complex” LVs and for optimizing diff payloads. But they also add complexity, force you (and team) into understanding more pieces and how they interact.

If you only need to handle events, you can do so in a LV. If you only need to build reusable components that render based on assigns, that’s what FC help you compose.

Where Next?

Popular in Questions Top

JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
RisingFromAshes
I’ve read in another post that it may be possible with a router helper - but I couldn’t find an appropriate one, and tbh, I’m still just ...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? Ecto.Repo — Ecto v3.14.0 has exampl...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New

Other popular topics Top

Qqwy
Update: How to use the Blogs &amp; Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3271 130286 1222
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 36654 110
New
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
985 44532 311
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New

We're in Beta

About us Mission Statement