Handling PubSub messages from within a LiveComponent?

Hello!

I have a LiveView that subscribes to a Phoenix.PubSub topic and shows some logs in real time. Now I want to move this part into a stateful LiveComponent, so that all logic regarding subscribing and reacting to messages in the topic lies within it.

But, I think this can’t be done - I can subscribe to the topic from within the LiveComponent, but it’s the parent LiveView process who is going to receive the messages, so I still need to have the handle_info logic in the parent LV process.

Is there something similar to phx-target="@myself" that can be used for PubSub like it’s done for events, so I can achieve this?

1 Like

The parent LV will always handle the messages, and then you can use those PubSub event handlers to pass the relevant changes to the child component(s).

2 Likes

Thanks, that’s what i thought… it would have been great to be have a LiveComponent that could be embedded into different LiveViews without needing them to know how to handle those messages!

1 Like

Hey folks, hi ! I reply to this topic as this is the issue that I have bumped into in a side project I am working on.

I have a website with some stateful components defined, like Navbar. Now, this component has a part which is rendered regardless any authentication state, and another one which is authentication dependent. This means that to an authenticated user a Logout button (among others) will be shown. Now, I have two options: I could potentially implement in the component the logout logic, or send a message to the parent which has to implement the logic, update the assigns, and by passing it to the Navbar component, update the page as a whole.

My issue with this is that in the latter scenario, every page which renders the component must know what to do to implement the logout; the former scenario looks the most reasonable, but I was trying to isolate the action associated to an event elsewhere, so to implement a full decoupling. Why should I do this ? Because I might reuse the component in another project where the logout meaning would potentially be different, and just leveraging messages and communication to trigger specific implementations to be pulled in and take care with super clear responsibility would be ideal, I think.

So I was thinking to let component to publish the event on pubsub; another component (for example, AuthenticationManager) would consume the message to execute proper logic; on the other side, any page which is rendering the Navbar component subscribes to a topic (for example, sessions:<user_id>) that could receive messages like {:logged_out, <user_id>} from the AuthenticationManager and simply update the assigns to propagate the change.

Anyway, apparently, this isn’t doable because of the parent views catching whatever message. Is this correct ? Is implementing the logic in the component the only way to do this ? And if this is true, is it correct to affirm that any page using the Navbar component should implement logic for any message that the component would generate ?

Sorry, I am just trying to avoid redundances.

If I understood correctly, you can use a LiveView on_mount hook, that subscribes to the events, uses attach_hook on the handle info callback, and then dispatches the relevant events to the component. This is what we do for Livebook’s sidebar: https://github.com/livebook-dev/livebook/blob/fa7244eae057499cb7088b83740977bfb7ce3fb1/lib/livebook_web/live/hooks/sidebar_hook.ex

It may make sense to allow the component to subscribe to the parent events, but one can imagine how this can become very confusing and hard to debug!

2 Likes

Hi @josevalim , the communication flow would be exactly the opposite.

  • components can send events to third parties entities (that know what to do when those events happen) via pubsub topic
  • liveview pages can subscribe to a pubsub topic
  • third party entities can subscribe to a topic to receive messages from components, execute some logic and send events to pages

The problem arises with the third party entities, which can’t receive message from components, that are instead received (apparently by design) by the component’s parents.

I haven’t yet read your link, I just wanted to specify (hopefully) better what’s my use case.