Subscribe on changes!

Multilayer teleport can not be remove completely

avatar
Apr 17th 2021

Version

3.0.11

Reproduction link

https://codepen.io/jsqy/pen/xxgJWdw

Steps to reproduce

This is just one example, the reality will be more complex, but the principle should be the same.

Reproduction link: Click the "change" button to control the alternate display of the two divs, but the teleport in the #pop does not uninstall with the uninstall of the div.

What is expected?

Because I often use teleport in components, and the component's slot may also contain teleport, the elements in the #pop are not completely unmounted.

What is actually happening?

A multi-layered teleport can cause exceptions.

avatar
Apr 18th 2021

This seems to be more an issue caused by the element re-use between v-if and v-else. Adding a key can be used as a workaround:

<div id="app">
    <div v-if="mode">
        Mode 1
        <teleport to="#pop" :disabled="dis">
            <div class="port" :key="1">
                Port 1
                <teleport to="#pop" :disabled="dis">
                    <div class="port" style="left: 200px;" :key="1">
                        Port 2
                    </div>
        </teleport>
            </div>
        </teleport>
    </div>
    <div v-else>
        Mode 2
        <teleport to="#pop" :disabled="dis">
            <div class="port" :key="2">
                Port 3
                <teleport to="#pop" :disabled="dis">
                    <div class="port" style="left: 200px;" :key="2">
                        Port 4
                    </div>
                </teleport>
            </div>
        </teleport>
    </div>
    <div>
        <input type="button" @click="mode = !mode" value="Change mode" /> <input type="button" @click="dis = !dis" value="Change disabled" />
    </div>
  <div>Click "Change mode" button multiple times, u can see a lot of "port2" and "port4", which is obviously not right.</div>
</div>
<div id="pop"></div>
avatar
Apr 18th 2021

I don't think this has anything to do with element re-use, but rather the nested teleport not being unmounted correctly.

image

When the el of Port1 was removed, Port2 was not removed correctly because it was mounted under pop. My idea was to set optimized to false on unmount if it contained a nested teleport. this may not be a good solution, so I didn't submit a PR.

Finally, I submitted a PR and didn't think of a better way.

avatar
Apr 18th 2021

This seems to be more an issue caused by the element re-use between v-if and v-else. Adding a key can be used as a workaround:

<div id="app">
    <div v-if="mode">
        Mode 1
        <teleport to="#pop" :disabled="dis">
            <div class="port" :key="1">
                Port 1
                <teleport to="#pop" :disabled="dis">
                    <div class="port" style="left: 200px;" :key="1">
                        Port 2
                    </div>
        </teleport>
            </div>
        </teleport>
    </div>
    <div v-else>
        Mode 2
        <teleport to="#pop" :disabled="dis">
            <div class="port" :key="2">
                Port 3
                <teleport to="#pop" :disabled="dis">
                    <div class="port" style="left: 200px;" :key="2">
                        Port 4
                    </div>
                </teleport>
            </div>
        </teleport>
    </div>
    <div>
        <input type="button" @click="mode = !mode" value="Change mode" /> <input type="button" @click="dis = !dis" value="Change disabled" />
    </div>
  <div>Click "Change mode" button multiple times, u can see a lot of "port2" and "port4", which is obviously not right.</div>
</div>
<div id="pop"></div>

I also don't think it has an issue with element re-use, I've written a new demo that doesn't involve v-if and v-else, and after clicking "Unmounted", only the first layer of teleport is destroyed.

The new link is: https://codepen.io/jsqy/pen/MWJqWLN

Examples written using v-if in the topic post are simply simplified problem reproduction, which is more complicated when combined with components, and the use of ":key"'s "workaround" does not solve the problem.