]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(reactivity): should add allowRecurse to the effect (#2213)
authorHcySunYang <HcySunYang@outlook.com>
Mon, 5 Oct 2020 20:36:02 +0000 (04:36 +0800)
committerGitHub <noreply@github.com>
Mon, 5 Oct 2020 20:36:02 +0000 (16:36 -0400)
So that the scheduler also respects effect's allowRecurse option.

fix #2200

packages/reactivity/src/effect.ts
packages/runtime-core/__tests__/rendererComponent.spec.ts

index 2d2b4d2a1bedd6d8af9d49349d639dea0893a4f2..683f8fa9e3cfc23ea9deb65e43c4c2a85cddda0a 100644 (file)
@@ -17,6 +17,7 @@ export interface ReactiveEffect<T = any> {
   raw: () => T
   deps: Array<Dep>
   options: ReactiveEffectOptions
+  allowRecurse: boolean
 }
 
 export interface ReactiveEffectOptions {
@@ -100,6 +101,7 @@ function createReactiveEffect<T = any>(
     }
   } as ReactiveEffect
   effect.id = uid++
+  effect.allowRecurse = !!options.allowRecurse
   effect._isEffect = true
   effect.active = true
   effect.raw = fn
@@ -180,7 +182,7 @@ export function trigger(
   const add = (effectsToAdd: Set<ReactiveEffect> | undefined) => {
     if (effectsToAdd) {
       effectsToAdd.forEach(effect => {
-        if (effect !== activeEffect || effect.options.allowRecurse) {
+        if (effect !== activeEffect || effect.allowRecurse) {
           effects.add(effect)
         }
       })
index d178c21e82ca614a01e755333d159bd427819c92..402a6732ddadcbcfe78f0a8ea770d7826c4dc47f 100644 (file)
@@ -8,7 +8,9 @@ import {
   VNode,
   provide,
   inject,
-  Ref
+  Ref,
+  watch,
+  SetupContext
 } from '@vue/runtime-test'
 
 describe('renderer: component', () => {
@@ -139,23 +141,21 @@ describe('renderer: component', () => {
   })
 
   // #2170
-  test('should have access to instance’s “$el” property in watcher when setting instance data', async () => {
+  test('should have access to instance’s “$el” property in watcher when rendereing with watched prop', async () => {
     function returnThis(this: any) {
       return this
     }
-    const dataWatchSpy = jest.fn(returnThis)
+    const propWatchSpy = jest.fn(returnThis)
     let instance: any
     const Comp = {
-      data() {
-        return {
-          testData: undefined
-        }
+      props: {
+        testProp: String
       },
 
       watch: {
-        testData() {
+        testProp() {
           // @ts-ignore
-          dataWatchSpy(this.$el)
+          propWatchSpy(this.$el)
         }
       },
 
@@ -170,50 +170,50 @@ describe('renderer: component', () => {
 
     const root = nodeOps.createElement('div')
     render(h(Comp), root)
+    await nextTick()
+    expect(propWatchSpy).not.toHaveBeenCalled()
 
-    expect(dataWatchSpy).not.toHaveBeenCalled()
-    instance.testData = 'data'
-
+    render(h(Comp, { testProp: 'prop ' }), root)
     await nextTick()
-    expect(dataWatchSpy).toHaveBeenCalledWith(instance.$el)
+    expect(propWatchSpy).toHaveBeenCalledWith(instance.$el)
   })
 
-  // #2170
-  test('should have access to instance’s “$el” property in watcher when rendereing with watched prop', async () => {
-    function returnThis(this: any) {
-      return this
-    }
-    const propWatchSpy = jest.fn(returnThis)
-    let instance: any
-    const Comp = {
-      props: {
-        testProp: String
-      },
+  // #2200
+  test('component child updating parent state in pre-flush should trigger parent re-render', async () => {
+    const outer = ref(0)
+    const App = {
+      setup() {
+        const inner = ref(0)
 
-      watch: {
-        testProp() {
-          // @ts-ignore
-          propWatchSpy(this.$el)
+        return () => {
+          return [
+            h('div', inner.value),
+            h(Child, {
+              value: outer.value,
+              onUpdate: (val: number) => (inner.value = val)
+            })
+          ]
         }
-      },
+      }
+    }
 
-      created() {
-        instance = this
-      },
+    const Child = {
+      props: ['value'],
+      setup(props: any, { emit }: SetupContext) {
+        watch(() => props.value, (val: number) => emit('update', val))
 
-      render() {
-        return h('div')
+        return () => {
+          return h('div', props.value)
+        }
       }
     }
 
     const root = nodeOps.createElement('div')
+    render(h(App), root)
+    expect(serializeInner(root)).toBe(`<div>0</div><div>0</div>`)
 
-    render(h(Comp), root)
-    await nextTick()
-    expect(propWatchSpy).not.toHaveBeenCalled()
-
-    render(h(Comp, { testProp: 'prop ' }), root)
+    outer.value++
     await nextTick()
-    expect(propWatchSpy).toHaveBeenCalledWith(instance.$el)
+    expect(serializeInner(root)).toBe(`<div>1</div><div>1</div>`)
   })
 })