Browse Source

fix: scoped slots should update when inside v-for

fix #9506
Evan You 7 years ago
parent
commit
8f004ea44e

+ 9 - 3
src/compiler/codegen/index.js

@@ -375,12 +375,18 @@ function genScopedSlots (
       containsSlotChild(slot) // is passing down slot from parent which may be dynamic
     )
   })
-  // OR when it is inside another scoped slot (the reactivity is disconnected)
-  // #9438
+  // OR when it is inside another scoped slot or v-for (the reactivity may be
+  // disconnected due to the intermediate scope variable)
+  // #9438, #9506
+  // TODO: this can be further optimized by properly analyzing in-scope bindings
+  // and skip force updating ones that do not actually use scope variables.
   if (!needsForceUpdate) {
     let parent = el.parent
     while (parent) {
-      if (parent.slotScope && parent.slotScope !== emptySlotScopeToken) {
+      if (
+        (parent.slotScope && parent.slotScope !== emptySlotScopeToken) ||
+        parent.for
+      ) {
         needsForceUpdate = true
         break
       }

+ 26 - 0
test/unit/features/component/component-scoped-slot.spec.js

@@ -1171,4 +1171,30 @@ describe('Component scoped slot', () => {
       expect(vm.$el.textContent).toBe('bar')
     }).then(done)
   })
+
+  it('should not skip updates for v-slot inside v-for', done => {
+    const test = {
+      template: `<div><slot></slot></div>`
+    }
+
+    const vm = new Vue({
+      template: `
+      <div>
+        <div v-for="i in numbers">
+          <test v-slot>{{ i }}</test>
+        </div>
+      </div>
+      `,
+      components: { test },
+      data: {
+        numbers: [1]
+      }
+    }).$mount()
+
+    expect(vm.$el.textContent).toBe(`1`)
+    vm.numbers = [2]
+    waitForUpdate(() => {
+      expect(vm.$el.textContent).toBe(`2`)
+    }).then(done)
+  })
 })