portal-vue icon indicating copy to clipboard operation
portal-vue copied to clipboard

Add a `keep-alive` mode so that the component is only teleported, not re-mounted

Open qnp opened this issue 3 years ago • 9 comments

Hello,

First-of-all, thanks for your amazing work.

Here is my use case : I have a very big resource-consuming Vue component – a wrapper of mapbox-gl-js with a lot of data transforms and layers computations – which is used in several parts of the webapp. However, in each place I need a map, I have a new instance of this component which has a strong overhead in terms of initialization and in terms of memory. Yet, it is always the "same" map with different props (center, zoom, layers, data, etc...).

My idea was to use portal-vue in order to have a unique instance of this map component, which props are plugged to a vuex store so accessible everywhere in the webapp, and when I need this map on a given part of the webapp, I just teleport it in it's reserved place by dynamically updating to prop of portal component.

However, each time to prop is updated, the child component is re-mounted. And this is what I want to avoid.

It would be great – if feasible – to have a keep-alive prop to portal component so that it is never destroyed and remounted, only teleported as-is in the new target.

What do you think ?

Best regards

qnp avatar Apr 01 '21 17:04 qnp

I have a similar use case... Any development!

ccwalkerjm avatar Jul 12 '21 11:07 ccwalkerjm

@LinusBorg I know you are involved in a lot of projects. I wanted to ping you in order to have your guidance about :

  1. The feasibility of such a feature (it may not be the case by design)
  2. Few steps in order to get started with contributing to this project.

Best,

qnp avatar Jul 12 '21 12:07 qnp

Hey there!

Awesome that you want to contribute :)

I have thought about how to achieve this for a while on and off, and haven't been able to come up with a solution.

For now I came to the conclusion that, it at all possible, it would be very hard to achieve, and it would require messing with the internals of Vue to a degree I don't feel comfortable, as it would make this package depend on internal APIs that might break easily.

The core of the issue is that this library moves the raw slot content (as vnodes / scoped Slot functions) from portal to target, not the actual DOM elements. it's the target that actually renders and owns the DOM, and it would require pretty significant rewiring and extension of the way this library works to also move this DOM around to new places.

We would also somehow re-parent and components nested in these slots, so that the $parent chain would stay intact etc.

I'm not saying it's impossible or must rely on risky APIs, but so far I haven't found a good way that does not end up there one way or another.

It might be more worth-while exploring a totally different approach (for a different package) where the "portal" transfers actual DOM, maybe?

LinusBorg avatar Jul 15 '21 20:07 LinusBorg

Just thinking; with the advent of Vue 3 with teleport, will this project still be viable?
Just to add, I actually use v-show with the disabled attribute to solve my problem.

ccwalkerjm avatar Jul 16 '21 12:07 ccwalkerjm

Vue 3's teleport doesn't really support teleportation between components. It's focus is to teleport to a stable target element outside of the Vue-controlled Dom. So the features of this lib are still useful in a range of scenarios, though the 80% use case of moving a modal/dialog/drop-down up to the body element is now better covered by Teleport.

I still ported this lib to Vue 3 (not in a final release) so people may migrate easier.

I have also started work on a new lib that would wrap <teleport> in a way that should enable teleportation between components safely, while using the native Vue mechanism which will allow to keep Dom alive during relocation.

I still have to iron a few things out, but hope to release a first version in a few weeks or so.

LinusBorg avatar Jul 16 '21 12:07 LinusBorg

@ccwalkerjm Interesting, can you provide me with a small example on how you use v-show with the disabled attribute ?

qnp avatar Jul 16 '21 15:07 qnp

I am working on a big Vue 2 web-app which won't be ported to Vue 3 for the next few years I guess, so this feature in Vue 2 would still be useful. I bet several companies have big Vue 2 projects and no enough resource to port the entire codebase to Vue 3.

qnp avatar Jul 16 '21 15:07 qnp

Thanks for your previous answer @LinusBorg

It might be more worth-while exploring a totally different approach (for a different package) where the "portal" transfers actual DOM, maybe?

I think this approach would be more relevant, however wouldn't we need to cleanly use Vue mechanics – with regular or deep internal APIs – for Vue to keep track of the updated virtual DOM ? Otherwise, we could completely mess with the internal update cycle and end up with a decoupled state between DOM and virtual DOM ?

qnp avatar Jul 16 '21 15:07 qnp

Thinking about it, my use case is totally different from yours.

In my case I have this situation. I have a component that needs to be shown in Modal or Not. I needed the same functionality whether modal or not. Note the way I use it below.

<template>
    <div>        
        <b-input-group @click="is_visible = true" v-if="isModal">
            <b-form-input readonly :value="se...."></b-form-input>
            <b-input-group-append>
                <b-button v-b-modal.lo....  variant="outline-primary">
                    <b-icon icon="arrows-angle-expand"></b-icon>
                </b-button>
            </b-input-group-append>
        </b-input-group>
        
        <b-modal
            v-if="isModal"
            v-model="is_visible"
            :title="modalTitle"
         
        >
            <portal-target name="loc...."></portal-target>
        </b-modal>
        
        <portal
            to="loc....."
            :disabled="!isModal || !is_visible"
            v-show="!isModal"
        >
            <b-card :title="title" title-tag="h6">
               
            </b-card>
        </portal>
    </div>
</template>

ccwalkerjm avatar Jul 16 '21 16:07 ccwalkerjm

Will close this as this won't be coming to portal-vue - not really feasable.

LinusBorg avatar Dec 10 '22 18:12 LinusBorg