]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
feat(core): respect $stable slots flag per RFC
authorEvan You <yyx990803@gmail.com>
Tue, 26 Nov 2019 15:03:36 +0000 (10:03 -0500)
committerEvan You <yyx990803@gmail.com>
Tue, 26 Nov 2019 15:03:36 +0000 (10:03 -0500)
packages/runtime-core/__tests__/component.spec.ts
packages/runtime-core/src/componentRenderUtils.ts
packages/runtime-core/src/componentSlots.ts

index b9483931ec440746017c8eb6e077765e98a836c8..566be0b826e68637b1d9722f0c1df90d0345a2cf 100644 (file)
@@ -1,3 +1,5 @@
+import { h, ref, render, nodeOps, nextTick } from '@vue/runtime-test'
+
 describe('renderer: component', () => {
   test.todo('should work')
 
@@ -7,5 +9,47 @@ describe('renderer: component', () => {
 
   test.todo('componentProps')
 
-  test.todo('componentSlots')
+  describe('slots', () => {
+    test('should respect $stable flag', async () => {
+      const flag1 = ref(1)
+      const flag2 = ref(2)
+      const spy = jest.fn()
+
+      const Child = () => {
+        spy()
+        return 'child'
+      }
+
+      const App = {
+        setup() {
+          return () => [
+            flag1.value,
+            h(
+              Child,
+              { n: flag2.value },
+              {
+                foo: () => 'foo',
+                $stable: true
+              }
+            )
+          ]
+        }
+      }
+
+      render(h(App), nodeOps.createElement('div'))
+      expect(spy).toHaveBeenCalledTimes(1)
+
+      // parent re-render, props didn't change, slots are stasble
+      // -> child should not update
+      flag1.value++
+      await nextTick()
+      expect(spy).toHaveBeenCalledTimes(1)
+
+      // parent re-render, props changed
+      // -> child should update
+      flag2.value++
+      await nextTick()
+      expect(spy).toHaveBeenCalledTimes(2)
+    })
+  })
 })
index 9510d3cb61c2dedc77c9168139e6516c163a3fe0..dbf68c879e6278af818801e5be28397ca4bf51dd 100644 (file)
@@ -138,7 +138,9 @@ export function shouldUpdateComponent(
     // this path is only taken by manually written render functions
     // so presence of any children leads to a forced update
     if (prevChildren != null || nextChildren != null) {
-      return true
+      if (nextChildren == null || !(nextChildren as any).$stable) {
+        return true
+      }
     }
     if (prevProps === nextProps) {
       return false
index 5821f38e85b7828fb0b4c0ae69156c8e7fc2fd38..583e12db645ff21264102ff3150f9c9d9d457fbe 100644 (file)
@@ -15,6 +15,9 @@ export type Slots = Readonly<InternalSlots>
 
 export type RawSlots = {
   [name: string]: unknown
+  // manual render fn hint to skip forced children updates
+  $stable?: boolean
+  // internal, indicates compiler generated slots = can skip normalization
   _compiled?: boolean
 }
 
@@ -49,6 +52,7 @@ export function resolveSlots(
     } else {
       slots = {}
       for (const key in rawSlots) {
+        if (key === '$stable') continue
         const value = rawSlots[key]
         if (isFunction(value)) {
           slots[key] = normalizeSlot(key, value)