expect(spy2).toHaveBeenCalledTimes(1)
})
+ it('watching reactive depth', async () => {
+ const state = reactive({
+ a: {
+ b: {
+ c: {
+ d: {
+ e: 1,
+ },
+ },
+ },
+ },
+ })
+
+ const cb = vi.fn()
+
+ watch(state, cb, { deep: 2 })
+
+ state.a.b = { c: { d: { e: 2 } } }
+ await nextTick()
+ expect(cb).toHaveBeenCalledTimes(1)
+
+ state.a.b.c = { d: { e: 3 } }
+
+ await nextTick()
+ expect(cb).toHaveBeenCalledTimes(1)
+
+ state.a.b = { c: { d: { e: 4 } } }
+
+ await nextTick()
+ expect(cb).toHaveBeenCalledTimes(2)
+ })
+
+ it('watching ref depth', async () => {
+ const state = ref({
+ a: {
+ b: 2,
+ },
+ })
+
+ const cb = vi.fn()
+
+ watch(state, cb, { deep: 1 })
+
+ state.value.a.b = 3
+ await nextTick()
+ expect(cb).toHaveBeenCalledTimes(0)
+
+ state.value.a = { b: 3 }
+ await nextTick()
+ expect(cb).toHaveBeenCalledTimes(1)
+ })
+
+ it('watching array depth', async () => {
+ const arr = ref([
+ {
+ a: {
+ b: 2,
+ },
+ },
+ {
+ a: {
+ b: 3,
+ },
+ },
+ ])
+ const cb = vi.fn()
+ watch(arr, cb, { deep: 2 })
+
+ arr.value[0].a.b = 3
+ await nextTick()
+ expect(cb).toHaveBeenCalledTimes(0)
+
+ arr.value[0].a = { b: 3 }
+ await nextTick()
+ expect(cb).toHaveBeenCalledTimes(1)
+
+ arr.value[1].a = { b: 4 }
+ await nextTick()
+ expect(cb).toHaveBeenCalledTimes(2)
+
+ arr.value.push({ a: { b: 5 } })
+ await nextTick()
+ expect(cb).toHaveBeenCalledTimes(3)
+
+ arr.value.pop()
+ await nextTick()
+ expect(cb).toHaveBeenCalledTimes(4)
+ })
+
+ it('shallowReactive', async () => {
+ const state = shallowReactive({
+ msg: ref('hello'),
+ foo: {
+ a: ref(1),
+ b: 2,
+ },
+ bar: 'bar',
+ })
+
+ const spy = vi.fn()
+
+ watch(state, spy)
+
+ state.msg.value = 'hi'
+ await nextTick()
+ expect(spy).not.toHaveBeenCalled()
+
+ state.bar = 'bar2'
+ await nextTick()
+ expect(spy).toHaveBeenCalledTimes(1)
+
+ state.foo.a.value++
+ state.foo.b++
+ await nextTick()
+ expect(spy).toHaveBeenCalledTimes(1)
+
+ state.bar = 'bar3'
+ await nextTick()
+ expect(spy).toHaveBeenCalledTimes(2)
+ })
+ it('watching reactive with deep: false', async () => {
+ const state = reactive({
+ foo: {
+ a: 2,
+ },
+ bar: 'bar',
+ })
+
+ const spy = vi.fn()
+
+ watch(state, spy, { deep: false })
+
+ state.foo.a++
+ await nextTick()
+ expect(spy).toHaveBeenCalledTimes(0)
+
+ state.bar = 'bar2'
+ await nextTick()
+ expect(spy).toHaveBeenCalledTimes(1)
+ })
+
test("effect should be removed from scope's effects after it is stopped", () => {
const num = ref(0)
let unwatch: () => void
export interface WatchOptions<Immediate = boolean> extends WatchOptionsBase {
immediate?: Immediate
- deep?: boolean
+ deep?: boolean | number
once?: boolean
}
}
}
- // TODO remove in 3.5
- if (__DEV__ && deep !== void 0 && typeof deep === 'number') {
- warn(
- `watch() "deep" option with number value will be used as watch depth in future versions. ` +
- `Please use a boolean instead to avoid potential breakage.`,
- )
- }
-
if (__DEV__ && !cb) {
if (immediate !== undefined) {
warn(
}
const instance = currentInstance
- const reactiveGetter = (source: object) =>
- deep === true
- ? source // traverse will happen in wrapped getter below
- : // for deep: false, only traverse root-level properties
- traverse(source, deep === false ? 1 : undefined)
+ const reactiveGetter = (source: object) => {
+ // traverse will happen in wrapped getter below
+ if (deep) return source
+ // for `deep: false | 0` or shallow reactive, only traverse root-level properties
+ if (isShallow(source) || deep === false || deep === 0)
+ return traverse(source, 1)
+ // for `deep: undefined` on a reactive object, deeply traverse all properties
+ return traverse(source)
+ }
let getter: () => any
let forceTrigger = false
if (cb && deep) {
const baseGetter = getter
- getter = () => traverse(baseGetter())
+ const depth = deep === true ? Infinity : deep
+ getter = () => traverse(baseGetter(), depth)
}
let cleanup: (() => void) | undefined