@@ -375,6 +375,13 @@ function genScopedSlots (
375
375
containsSlotChild ( slot ) // is passing down slot from parent which may be dynamic
376
376
)
377
377
} )
378
+
379
+ // #9534: if a component with scoped slots is inside a conditional branch,
380
+ // it's possible for the same component to be reused but with different
381
+ // compiled slot content. To avoid that, we generate a unique key based on
382
+ // the generated code of all the slot contents.
383
+ let needsKey = ! ! el . if
384
+
378
385
// OR when it is inside another scoped slot or v-for (the reactivity may be
379
386
// disconnected due to the intermediate scope variable)
380
387
// #9438, #9506
@@ -390,15 +397,31 @@ function genScopedSlots (
390
397
needsForceUpdate = true
391
398
break
392
399
}
400
+ if ( parent . if ) {
401
+ needsKey = true
402
+ }
393
403
parent = parent . parent
394
404
}
395
405
}
396
406
397
- return `scopedSlots:_u([${
398
- Object . keys ( slots ) . map ( key => {
399
- return genScopedSlot ( slots [ key ] , state )
400
- } ) . join ( ',' )
401
- } ]${ needsForceUpdate ? `,true` : `` } )`
407
+ const generatedSlots = Object . keys ( slots )
408
+ . map ( key => genScopedSlot ( slots [ key ] , state ) )
409
+ . join ( ',' )
410
+
411
+ return `scopedSlots:_u([${ generatedSlots } ]${
412
+ needsForceUpdate ? `,true` : ``
413
+ } ${
414
+ ! needsForceUpdate && needsKey ? `,false,${ hash ( generatedSlots ) } ` : ``
415
+ } )`
416
+ }
417
+
418
+ function hash ( str ) {
419
+ let hash = 5381
420
+ let i = str . length
421
+ while ( i ) {
422
+ hash = ( hash * 33 ) ^ str . charCodeAt ( -- i )
423
+ }
424
+ return hash >>> 0
402
425
}
403
426
404
427
function containsSlotChild ( el : ASTNode ) : boolean {
0 commit comments