Hey! I have the following use-case: a list of messages that is being displayed in the UI and using phx-update=“stream” to optimize changes on updates.
Each message is its own live_component that handles a “streaming-like” effect using send_update_after
with the chunk of the message I want to update on the UI.
I also have a phx-hook that contains a MutationObserver
to check on a specific custom data attribute data-we-streaming
. Everytime there’s a change on this data attribute or in the element childList, an event is pushed to the live_view to inform it if there’s any element streaming at the moment.
Code-wise it looks something like this:
<div phx-update="stream" phx-hook="streamingController">
<%= for {dom_id, message} <- @streams.ui_messages do %>
<.live_component module={MyLiveComponent} message={message} />
<% end %>
</div>
And the hook:
const hook: Hook<StreamingControllerHook> & StreamingControllerHook = {
mounted() {
this.pushEvent('streaming-status', { isStreaming : !!this.el.querySelector('[data-we-streaming]') });
// Create a MutationObserver to watch for DOM changes
this.observer = new MutationObserver((mutations) => {
const shouldPushEvent = mutations.some((mutation) => mutation.type === 'attributes' || mutation.type === 'childList');
if (shouldPushEvent) {
this.pushEvent('streaming-status', { isStreaming : !!this.el.querySelector('[data-we-streaming]') });
}
});
// Start observing the entire document for changes
this.observer.observe(this.el, {
childList : true,
subtree : true,
attributes : true,
attributeFilter : ['data-we-streaming'],
});
},
updated() {
this.pushEvent('streaming-status', { isStreaming : !!this.el.querySelector('[data-we-streaming]') });
},
destroyed() {
// Clean up the observer when the hook is destroyed
if (this.observer) {
this.observer.disconnect();
}
},
};
It all was working fine until I pushed this code to PRD: sometimes and in some browsers, the fake streaming behavior just freezes and the user gets stuck (since there is some conditional logic for the user to progress ONLY when no element is streaming).
My question is: can this be caused by the existence of a live_component inside of an element that contains a stream
strategy? Or theoretically there shouldn’t exist any blockers with this approach?
Thanks for your time,
Sara