From ea1f87eabf2deab2e586af7ebd2d74bb58f72b87 Mon Sep 17 00:00:00 2001 From: HcySunYang Date: Tue, 6 Oct 2020 04:36:02 +0800 Subject: [PATCH] fix(reactivity): should add allowRecurse to the effect (#2213) So that the scheduler also respects effect's allowRecurse option. fix #2200 --- packages/reactivity/src/effect.ts | 4 +- .../__tests__/rendererComponent.spec.ts | 84 +++++++++---------- 2 files changed, 45 insertions(+), 43 deletions(-) diff --git a/packages/reactivity/src/effect.ts b/packages/reactivity/src/effect.ts index 2d2b4d2a1..683f8fa9e 100644 --- a/packages/reactivity/src/effect.ts +++ b/packages/reactivity/src/effect.ts @@ -17,6 +17,7 @@ export interface ReactiveEffect { raw: () => T deps: Array options: ReactiveEffectOptions + allowRecurse: boolean } export interface ReactiveEffectOptions { @@ -100,6 +101,7 @@ function createReactiveEffect( } } 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 | undefined) => { if (effectsToAdd) { effectsToAdd.forEach(effect => { - if (effect !== activeEffect || effect.options.allowRecurse) { + if (effect !== activeEffect || effect.allowRecurse) { effects.add(effect) } }) diff --git a/packages/runtime-core/__tests__/rendererComponent.spec.ts b/packages/runtime-core/__tests__/rendererComponent.spec.ts index d178c21e8..402a6732d 100644 --- a/packages/runtime-core/__tests__/rendererComponent.spec.ts +++ b/packages/runtime-core/__tests__/rendererComponent.spec.ts @@ -8,7 +8,9 @@ import { VNode, provide, inject, - Ref + Ref, + watch, + SetupContext } from '@vue/runtime-test' describe('renderer: component', () => { @@ -138,46 +140,6 @@ describe('renderer: component', () => { expect(serializeInner(root)).toBe(`
1
1
`) }) - // #2170 - test('should have access to instance’s “$el” property in watcher when setting instance data', async () => { - function returnThis(this: any) { - return this - } - const dataWatchSpy = jest.fn(returnThis) - let instance: any - const Comp = { - data() { - return { - testData: undefined - } - }, - - watch: { - testData() { - // @ts-ignore - dataWatchSpy(this.$el) - } - }, - - created() { - instance = this - }, - - render() { - return h('div') - } - } - - const root = nodeOps.createElement('div') - render(h(Comp), root) - - expect(dataWatchSpy).not.toHaveBeenCalled() - instance.testData = 'data' - - await nextTick() - expect(dataWatchSpy).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) { @@ -207,7 +169,6 @@ describe('renderer: component', () => { } const root = nodeOps.createElement('div') - render(h(Comp), root) await nextTick() expect(propWatchSpy).not.toHaveBeenCalled() @@ -216,4 +177,43 @@ describe('renderer: component', () => { await nextTick() expect(propWatchSpy).toHaveBeenCalledWith(instance.$el) }) + + // #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) + + return () => { + return [ + h('div', inner.value), + h(Child, { + value: outer.value, + onUpdate: (val: number) => (inner.value = val) + }) + ] + } + } + } + + const Child = { + props: ['value'], + setup(props: any, { emit }: SetupContext) { + watch(() => props.value, (val: number) => emit('update', val)) + + return () => { + return h('div', props.value) + } + } + } + + const root = nodeOps.createElement('div') + render(h(App), root) + expect(serializeInner(root)).toBe(`
0
0
`) + + outer.value++ + await nextTick() + expect(serializeInner(root)).toBe(`
1
1
`) + }) })