Open vheathen opened 5 months ago
@vheathen Great points! I'll try to explain why it looks as it looks:
You can't mount standalone Vue component into a page. It always has to be wrapped by top-level app created with createApp
. I don't see a way of having a single Vue app mounted into multiple places (maybe portals? but it would be quite complex and might cause bugs).
To keep slots interactive, they're fully rendered on the server and sent as an HTML over the wire. In other words, they doesn't use phoenix-driven update & render cycle since I couldn't find a way of making it work (once Vue "takes over" rendering phoenix can't update & execute hooks inside). So currently content in slots can't use phoenix hook - it's the same as in LiveSvelte. If you could find a way to make it work, it would be amazing :)
To emit events directly to live view from a nested compontent you can use
import {useLiveVue} from "live_vue"
const live = useLiveVue()
live.pushEvent("ping")
or you can subscribe to handle custom events as well. useLiveVue
gives you the hook instance, so you can use anything from JS interoperability.
state
component that would synchronize passed props to reactive
object on the frontend, so it could be shared by multiple components, if necessary. But right now it's just a thought 😉
Seems that currently it's not possible to have nested LiveVue components added via slots
Here is an example:
Card is a very simple Vue component which has only a slot inside:
The very first Counter.vue disappears (this is slightly visually modified module included to LiveVue) disappears after the view mounted to the server.
The second one is there, but it doesn't have any state or behaviour - event the slider itself doesn't change the button label.
The third one - which is outside of the Card - is working as intended.
Funny enough that the top visible Counter gets one update when the server state changes the first time (the first "Increase counter" click) but then it stops.
I tried to look into the code but haven't found a good way to implement the case above.
Also, I noticed that each component gets its own application instance. I wonder if it makes sense to have only one app? In this case components can share state. Or it can be configurable. Don't think it worth spending time on that now TBH, but in the future can be interesting.
But the question is how should nested Vue components behave is an interesting topic. Currently to change server state from the nested Vue components (I mean, actual Vue components without anything in-between) it is necessary to emit events from the bottom to the top level one, which is actually got a VueHook, and then this component will emit an event to the LiveView controller.
May be an option here is to implement a server-side reactive store of some kind? It is possible to integrate pinia, but it will be too heavy only for that purpose, I think.
Anyway, I believe this topic worth another thread :-D