]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
refactor(scheduler): remove invalidateJob (#11650)
authorskirtle <65301168+skirtles-code@users.noreply.github.com>
Mon, 19 Aug 2024 02:49:59 +0000 (03:49 +0100)
committerGitHub <noreply@github.com>
Mon, 19 Aug 2024 02:49:59 +0000 (10:49 +0800)
Co-authored-by: Evan You <evan@vuejs.org>
packages/runtime-core/__tests__/rendererComponent.spec.ts
packages/runtime-core/__tests__/scheduler.spec.ts
packages/runtime-core/src/renderer.ts
packages/runtime-core/src/scheduler.ts

index c5faa05de83c71697cd749fa81200bc5549ecd23..fefc4137034f98d1407958330d63a65b596a4272 100644 (file)
@@ -236,6 +236,105 @@ describe('renderer: component', () => {
     expect(serializeInner(root)).toBe(`<div>1</div><div>1</div>`)
   })
 
+  test('child only updates once when triggered in multiple ways', async () => {
+    const a = ref(0)
+    const calls: string[] = []
+
+    const Parent = {
+      setup() {
+        return () => {
+          calls.push('render parent')
+          return h(Child, { count: a.value }, () => a.value)
+        }
+      },
+    }
+
+    const Child = {
+      props: ['count'],
+      setup(props: any) {
+        return () => {
+          calls.push('render child')
+          return `${props.count} - ${a.value}`
+        }
+      },
+    }
+
+    render(h(Parent), nodeOps.createElement('div'))
+    expect(calls).toEqual(['render parent', 'render child'])
+
+    // This will trigger child rendering directly, as well as via a prop change
+    a.value++
+    await nextTick()
+    expect(calls).toEqual([
+      'render parent',
+      'render child',
+      'render parent',
+      'render child',
+    ])
+  })
+
+  // #7745
+  test(`an earlier update doesn't lead to excessive subsequent updates`, async () => {
+    const globalCount = ref(0)
+    const parentCount = ref(0)
+    const calls: string[] = []
+
+    const Root = {
+      setup() {
+        return () => {
+          calls.push('render root')
+          return h(Parent, { count: globalCount.value })
+        }
+      },
+    }
+
+    const Parent = {
+      props: ['count'],
+      setup(props: any) {
+        return () => {
+          calls.push('render parent')
+          return [
+            `${globalCount.value} - ${props.count}`,
+            h(Child, { count: parentCount.value }),
+          ]
+        }
+      },
+    }
+
+    const Child = {
+      props: ['count'],
+      setup(props: any) {
+        watch(
+          () => props.count,
+          () => {
+            calls.push('child watcher')
+            globalCount.value = props.count
+          },
+        )
+
+        return () => {
+          calls.push('render child')
+        }
+      },
+    }
+
+    render(h(Root), nodeOps.createElement('div'))
+    expect(calls).toEqual(['render root', 'render parent', 'render child'])
+
+    parentCount.value++
+    await nextTick()
+    expect(calls).toEqual([
+      'render root',
+      'render parent',
+      'render child',
+      'render parent',
+      'child watcher',
+      'render child',
+      'render root',
+      'render parent',
+    ])
+  })
+
   // #2521
   test('should pause tracking deps when initializing legacy options', async () => {
     let childInstance = null as any
index 8d74330da44897735928c587195fabae9cb03133..5c5b04673abad4fb858b869422868bb71a928bbf 100644 (file)
@@ -3,7 +3,6 @@ import {
   SchedulerJobFlags,
   flushPostFlushCbs,
   flushPreFlushCbs,
-  invalidateJob,
   nextTick,
   queueJob,
   queuePostFlushCb,
@@ -444,33 +443,6 @@ describe('scheduler', () => {
     })
   })
 
-  test('invalidateJob', async () => {
-    const calls: string[] = []
-    const job1 = () => {
-      calls.push('job1')
-      invalidateJob(job2)
-      job2()
-    }
-    const job2 = () => {
-      calls.push('job2')
-    }
-    const job3 = () => {
-      calls.push('job3')
-    }
-    const job4 = () => {
-      calls.push('job4')
-    }
-    // queue all jobs
-    queueJob(job1)
-    queueJob(job2)
-    queueJob(job3)
-    queuePostFlushCb(job4)
-    expect(calls).toEqual([])
-    await nextTick()
-    // job2 should be called only once
-    expect(calls).toEqual(['job1', 'job2', 'job3', 'job4'])
-  })
-
   test('sort job based on id', async () => {
     const calls: string[] = []
     const job1 = () => calls.push('job1')
index 3d1cc6849c70a49b3673b26f0faef478d390e3c4..ce0639895029aae1ead760935b3361a45a434386 100644 (file)
@@ -45,7 +45,6 @@ import {
   type SchedulerJobs,
   flushPostFlushCbs,
   flushPreFlushCbs,
-  invalidateJob,
   queueJob,
   queuePostFlushCb,
 } from './scheduler'
@@ -1255,9 +1254,6 @@ function baseCreateRenderer(
       } else {
         // normal update
         instance.next = n2
-        // in case the child component is also queued, remove it to avoid
-        // double updating the same child component in the same flush.
-        invalidateJob(instance.update)
         // instance.update is the reactive effect.
         instance.update()
       }
index 256ab202780f4682dad9f1abe7ae6f5d6afe9c75..aa12b6896a7f7b96d9433cd1cc8aa95b7ab9e006 100644 (file)
@@ -122,13 +122,6 @@ function queueFlush() {
   }
 }
 
-export function invalidateJob(job: SchedulerJob): void {
-  const i = queue.indexOf(job)
-  if (i > flushIndex) {
-    queue.splice(i, 1)
-  }
-}
-
 export function queuePostFlushCb(cb: SchedulerJobs): void {
   if (!isArray(cb)) {
     if (activePostFlushCbs && cb.id === -1) {