Vue: Unexpected "duplicate presence of slot"

Created on 28 Mar 2018  ·  9Comments  ·  Source: vuejs/vue

Version

2.5.2

Reproduction link

https://codesandbox.io/s/mzvkppmvo8

Steps to reproduce

  1. I created component with scoped slot (AppSwitcher.vue)
  2. Then I use it in another component with their own slot (HelloWorld.vue with slot "subtext")
  3. Add some element to slot (div in App.vue)

What is expected?

It should work without errors

What is actually happening?

Changes in AppSwitcher.vue caus "Duplicate presence of slot "subtext" found in the same render tree" error but there are no duplicates.


Also, adding slot-scope to div in App.vue solves problem and no error there, but why it happens without slot-scope?

bug has PR

Most helpful comment

I'm experiencing the same thing. Anything that triggers a re-render inside the slot-scope causes a warning about duplicate slot presence.

The issue seems to be here on this line here. Once the slots have been rendered once, subsequent executions of that block have slotNodes._rendered as true, presumably from the first render.

I would imagine something should be setting that back to false when a re-render is triggered, but admittedly I know almost nothing about how Vue works under the hood so that's just a wild guess.

This bug seems like an unlikely edge case but it's happened to me a couple of times recently. I'm a big fan of the pattern of writing renderless components that can be paired with concrete implementations, and trying to pass the content from the consumer into the concrete implementation is when this issue is arising.

All 9 comments

Hello @Kelin2025

In v2.5, there was some changes in scoped-slot, you can go through them here - https://gist.github.com/yyx990803/9bdff05e5468a60ced06c29c39114c6b#simplified-scoped-slots-usage

This might solve your confusion

Yeah, I know it, but I don't really understand why I get this error, there are no __duplicates__ of slot but only rerender.

It looks like a slot inside a scoped slot is rendered more than once.

@Justineo it's being re-rendered on changes but it shouldn't cause problems, I think :thinking:

My 2 cents.

Here is another reproduction of this issue (https://codesandbox.io/s/m5kl6p97qx). Notice the warning being raised only once the modal is shown more than once.

On the other hand, the JSX version of the same component is not raising any warning (https://codesandbox.io/s/k0wpj60z5r).

I'm experiencing the same thing. Anything that triggers a re-render inside the slot-scope causes a warning about duplicate slot presence.

The issue seems to be here on this line here. Once the slots have been rendered once, subsequent executions of that block have slotNodes._rendered as true, presumably from the first render.

I would imagine something should be setting that back to false when a re-render is triggered, but admittedly I know almost nothing about how Vue works under the hood so that's just a wild guess.

This bug seems like an unlikely edge case but it's happened to me a couple of times recently. I'm a big fan of the pattern of writing renderless components that can be paired with concrete implementations, and trying to pass the content from the consumer into the concrete implementation is when this issue is arising.

try this:
my-component:

<template>
    <slot :someprop="value"></slot>
</template>

app:

<my-component>
    <template slot-scop="someprop">{{ prop }} ... and do something else</template>
</my-component>

especially when "slot" in "v-for"

Note that if you're using Vue.js ≤v2.4.x, then you may see this error if you are trying to use slot-scope (that's what was going on for me).

The solution is to either update Vue.js to ≥2.5 OR use "scope" instead of "slot-scope":

image
_https://vuejs.org/v2/api/#scope-replaced_

Hope that helps anyone else finding this on google like I did!


PS. If you're using Vue.js ≤v2.4.x, remember that you'll need to use a <template> element -- you can't just put a slot scope boundary on any miscellaneous element until ≥2.5.x. A little real-world example:

      <div class="form-group col-md">
        <label>Autocomplete field 4 (w/ custom search results):</label>
        <autocomplete v-model="autocompleteExampleValue4" action="listGlobalSearchResults" :handle-formatting-response-data="handleFormattingDummySearchResults" placeholder="This one has a custom placeholder too">
          <template slot="search-result-item" scope="slotData"><!-- Note that you can use destructuring here, but it only works in modern browsers -- otherwise you have to define a separate variable -- like scope="slotData" and then use {{slotData.id}}... (see https://vuejs.org/v2/guide/components-slots.html#Destructuring-slot-scope) -->
            <!-- TODO: update to vue ≥ 2.5.0 to allow this slotData thing to be attached w/o using a template element.  Also when we do that, "scope" will become "slot-scope".  See https://vuejs.org/v2/guide/components-slots.html#Scoped-Slots for more info -->
            <span>{{slotData.searchResult.label}}</span>
          </template>
        </autocomplete>
      </div>

The solution is to either update Vue.js to ≥2.5 OR use "scope" instead of "slot-scope":

I still have this issue on 2.5.17.

It's really annoying when trying to build renderless component abstractions, as this comes up quite often.

Was this page helpful?
0 / 5 - 0 ratings