diff --git a/src/core/vdom/helpers/normalize-scoped-slots.js b/src/core/vdom/helpers/normalize-scoped-slots.js index cc0348f6550..1e43fd393f7 100644 --- a/src/core/vdom/helpers/normalize-scoped-slots.js +++ b/src/core/vdom/helpers/normalize-scoped-slots.js @@ -10,8 +10,8 @@ export function normalizeScopedSlots ( prevSlots?: { [key: string]: Function } | void ): any { let res - const isStable = slots ? !!slots.$stable : true const hasNormalSlots = Object.keys(normalSlots).length > 0 + const isStable = slots ? !!slots.$stable : !hasNormalSlots const key = slots && slots.$key if (!slots) { res = {} diff --git a/test/unit/features/component/component-scoped-slot.spec.js b/test/unit/features/component/component-scoped-slot.spec.js index 8960d8bf8c5..f8a0f11b7fa 100644 --- a/test/unit/features/component/component-scoped-slot.spec.js +++ b/test/unit/features/component/component-scoped-slot.spec.js @@ -1277,4 +1277,36 @@ describe('Component scoped slot', () => { }).$mount() expect(vm.$el.textContent).toMatch('fallback') }) + + // #9699 + // Component only has normal slots, but is passing down $scopedSlots directly + // $scopedSlots should not be marked as stable in this case + it('render function passing $scopedSlots w/ normal slots down', done => { + const one = { + template: `
` + } + + const two = { + render(h) { + return h(one, { + scopedSlots: this.$scopedSlots + }) + } + } + + const vm = new Vue({ + data: { count: 0 }, + render(h) { + return h(two, [ + h('span', { slot: 'footer' }, this.count) + ]) + } + }).$mount() + + expect(vm.$el.textContent).toMatch(`0`) + vm.count++ + waitForUpdate(() => { + expect(vm.$el.textContent).toMatch(`1`) + }).then(done) + }) })