Are there examples of complex LiveComponents nesting?

As much working with LiveViews has been fun for me so far, its has also been difficult to deal with complex interactions of LiveComponents. I just don’t understand how they are supposed to be used in complex use cases when communication is needed between stateful LiveComponents.

For that reason I am looking for examples that make use of stateful LiveComponents that communicate directly between them without requiring their events to be handled by the LiveView.

Well, basically, you can do all of this with LiveView, however things get complicated if you want to have independent components which state is not handled by the LiveView but only inside the LiveComponents.
Here is what I have experienced:

  • choosing between a LiveView or a LiveComponent becomes not trivial: more than once, I had to rewrite a component as a LiveView or as a LiveComponent because, at some point, I needed a feature that was only possible in one or the other (eg. live_patch in a LiveComponent of nested LiveView).
  • LiveViews and LiveComponents both allow you to create “web components” but their APIs are different: in some cases, to update the state you use either Process.send (or similar) in LiveViews or send_update for LiveComponents.
  • send_update only targets self so it is not possible to call it inside a spawn to perform an asynchronous task.
  • I experienced a weird behaviour when using send_update while updating (eg: send_update triggers update that in turn triggers another send_update on another LiveComponent): the update would only work every other time.
  • Handling PubSub events within a LiveComponent is not possible (or at least not without some additionnal effort that is not required for a LiveView): the LiveView is the process, so only it can implement the handle_info.

At this point I feel like I should only write LIveViews and use PubSub to communicate between them but maybe I am wrong.

I am still an Elixir/Phoenix/LiveView beginner, so maybe I am doing it all wrong. That’s why any examples and hints on how to handle such use case would be appreciated.

Thank you.

3 Likes

Have you taken a look at Surface (http://surface-demo.msaraiva.io/) - it doesn’t solve all the problems you mention (particularly the handle_info situation) but it does model event handling between controls / components a whole lot better IMO, and makes it easier to fully manage the logic for a component with the component code.

I’ve been thinking through this a fair bit recently as I’m looking at building a specialised configurable dashboard where I ideally want all the dashboard panes to be able to communicate but also operate independently. For example, a date selector on the page should apply to all dashboard panes, but each dashboard pane may also receive updates independently from multiple background processes.

The best model I can come up with is:
Dashboard panes would be modelled as separate liveviews. Each is therefore a separate process able to handle_info
For the dashboard panes to communicate between themselves, the hosting “page” (almost certainly a parent liveview) would create a unique id on mount and pass it to each dashboard pane for the purpose of setting up page-specific pubsub topic.
Complex control hierarchies which don’t need to handle_info are most likely going to be implemented in Surface.

If you have lots of communication between the components and the outside world then yes, this probably makes sense and more or less how I’m planning to approach it. If most of the communication is between the parent and the components, then take a good look at Surface. If it is mostly between components talking to each other then maybe spell out your use case a little more. There may be a different way to think about things.

3 Likes

Thanks @mindok for your input.

Yes I know about Surface. Well, LiveView itself is not considered stable yet, I am not comfortable using another unstable tool above it, to be honest. But I do like to concept of Surface with its Vue2.js influences.

I think I will give a try at the full LiveView solution with PubSub. Moreover, I like the publish/subscribe model, and I know from experience it can accommodate complex communication scenarios without too much effort.

I am just not sure what is the performance impact by using exclusively LiveViews. But from what I understand from Elixir processes, this should not be an issue.

Thanks.

1 Like

I have an example of somewhat complex nested LiveComponents. It’s not doing anything async, and, in fact, LiveView itself is empty and delegates all work to components.

It’s basically a CRUD tool where you can add Boxes and Things tha go inside boxes, with some rules on when/how buttons and forms are visible, so that you don’t add multiple empty boxes etc.

And the code can be found on my Github repo:


specifically the components themselves:

I didn’t have the need to do anything asynchronous in each component and it’s actually interesting question how would one do that with LiveComponents. But even within LivieComponents, you could start new processes to perform some tasks and those processes could send back the LiveView process a message requesting it to update:

This is what send_update does, and I don’t see the reason why it wouldn’t work if you wanted to send LiveView updates from some other than current process. Possibly using private API would be a downside, but I could live with that I think.

3 Likes