From b476f73647fec96fb15fed570872f8aa3b6611ce Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Wed, 11 Jan 2023 16:41:03 +0100 Subject: [PATCH 1/2] fix(reactivity): `triggerRef` working with `toRef` from reactive --- packages/reactivity/src/effect.ts | 2 +- packages/reactivity/src/ref.ts | 5 +++ .../runtime-core/__tests__/apiWatch.spec.ts | 41 +++++++++++++------ 3 files changed, 34 insertions(+), 14 deletions(-) diff --git a/packages/reactivity/src/effect.ts b/packages/reactivity/src/effect.ts index 9ef38c1b065..d9805bed388 100644 --- a/packages/reactivity/src/effect.ts +++ b/packages/reactivity/src/effect.ts @@ -16,7 +16,7 @@ import { ComputedRefImpl } from './computed' // which maintains a Set of subscribers, but we simply store them as // raw Sets to reduce memory overhead. type KeyToDepMap = Map -const targetMap = new WeakMap() +export const targetMap = new WeakMap() // The number of effects currently being tracked recursively. let effectTrackDepth = 0 diff --git a/packages/reactivity/src/ref.ts b/packages/reactivity/src/ref.ts index 26c6fe192ba..74b4b801d82 100644 --- a/packages/reactivity/src/ref.ts +++ b/packages/reactivity/src/ref.ts @@ -1,6 +1,7 @@ import { activeEffect, shouldTrack, + targetMap, trackEffects, triggerEffects } from './effect' @@ -228,6 +229,10 @@ class ObjectRefImpl { set value(newVal) { this._object[this._key] = newVal } + + get dep(): Dep | undefined { + return targetMap.get(toRaw(this._object))?.get(this._key) + } } export type ToRef = IfAny, [T] extends [Ref] ? T : Ref> diff --git a/packages/runtime-core/__tests__/apiWatch.spec.ts b/packages/runtime-core/__tests__/apiWatch.spec.ts index 6de8f95dec6..e9ab368d335 100644 --- a/packages/runtime-core/__tests__/apiWatch.spec.ts +++ b/packages/runtime-core/__tests__/apiWatch.spec.ts @@ -29,7 +29,8 @@ import { triggerRef, shallowRef, Ref, - effectScope + effectScope, + toRef } from '@vue/reactivity' // reference: https://vue-composition-api-rfc.netlify.com/api.html#watch @@ -925,6 +926,25 @@ describe('api: watch', () => { expect(spy).toHaveBeenCalledTimes(1) }) + test('should force trigger on triggerRef with toRef from reactive', async () => { + const foo = reactive({ bar: 1 }) + const bar = toRef(foo, 'bar') + const spy = jest.fn() + + watchEffect(() => { + bar.value + spy() + }) + + expect(spy).toHaveBeenCalledTimes(1) + + triggerRef(bar) + + await nextTick() + // should trigger now + expect(spy).toHaveBeenCalledTimes(2) + }) + // #2125 test('watchEffect should not recursively trigger itself', async () => { const spy = jest.fn() @@ -1158,23 +1178,18 @@ describe('api: watch', () => { const Comp = { setup() { effectScope(true).run(() => { - watchEffect( - () => { - trigger.value - countWE++ - }, - ) - watch( - trigger, - () => countW++ - ) + watchEffect(() => { + trigger.value + countWE++ + }) + watch(trigger, () => countW++) }) return () => '' } } const root = nodeOps.createElement('div') render(h(Comp), root) - // only watchEffect as ran so far + // only watchEffect as ran so far expect(countWE).toBe(1) expect(countW).toBe(0) trigger.value++ @@ -1186,7 +1201,7 @@ describe('api: watch', () => { await nextTick() trigger.value++ await nextTick() - // both watchers run again event though component has been unmounted + // both watchers run again event though component has been unmounted expect(countWE).toBe(3) expect(countW).toBe(2) }) From 8df72ed0e97ece9fc2fe669049a8268fa5d89a21 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Thu, 12 Jan 2023 13:10:06 +0100 Subject: [PATCH 2/2] chore: refactor --- packages/reactivity/src/effect.ts | 6 +++++- packages/reactivity/src/ref.ts | 11 ++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/reactivity/src/effect.ts b/packages/reactivity/src/effect.ts index d9805bed388..5eb84bc48d7 100644 --- a/packages/reactivity/src/effect.ts +++ b/packages/reactivity/src/effect.ts @@ -16,7 +16,7 @@ import { ComputedRefImpl } from './computed' // which maintains a Set of subscribers, but we simply store them as // raw Sets to reduce memory overhead. type KeyToDepMap = Map -export const targetMap = new WeakMap() +const targetMap = new WeakMap() // The number of effects currently being tracked recursively. let effectTrackDepth = 0 @@ -377,3 +377,7 @@ function triggerEffect( } } } + +export function getDepFromReactive(object: any, key: string | number | symbol) { + return targetMap.get(object)?.get(key) +} diff --git a/packages/reactivity/src/ref.ts b/packages/reactivity/src/ref.ts index 74b4b801d82..124e2aaa869 100644 --- a/packages/reactivity/src/ref.ts +++ b/packages/reactivity/src/ref.ts @@ -1,7 +1,7 @@ import { activeEffect, + getDepFromReactive, shouldTrack, - targetMap, trackEffects, triggerEffects } from './effect' @@ -54,16 +54,17 @@ export function trackRefValue(ref: RefBase) { export function triggerRefValue(ref: RefBase, newVal?: any) { ref = toRaw(ref) - if (ref.dep) { + const dep = ref.dep + if (dep) { if (__DEV__) { - triggerEffects(ref.dep, { + triggerEffects(dep, { target: ref, type: TriggerOpTypes.SET, key: 'value', newValue: newVal }) } else { - triggerEffects(ref.dep) + triggerEffects(dep) } } } @@ -231,7 +232,7 @@ class ObjectRefImpl { } get dep(): Dep | undefined { - return targetMap.get(toRaw(this._object))?.get(this._key) + return getDepFromReactive(toRaw(this._object), this._key) } }