feat(watch): support directly watching reactive object in multiple sources with deep default (#1201)
This commit is contained in:
parent
83b7158017
commit
ba62ccd55d
@ -155,12 +155,30 @@ describe('api: watch', () => {
|
|||||||
expect(dummy).toMatchObject([[2, true], [1, false]])
|
expect(dummy).toMatchObject([[2, true], [1, false]])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('watching multiple sources: reactive object (with automatic deep: true)', async () => {
|
||||||
|
const src = reactive({ count: 0 })
|
||||||
|
let dummy
|
||||||
|
watch([src], ([state]) => {
|
||||||
|
dummy = state
|
||||||
|
// assert types
|
||||||
|
state.count === 1
|
||||||
|
})
|
||||||
|
src.count++
|
||||||
|
await nextTick()
|
||||||
|
expect(dummy).toMatchObject({ count: 1 })
|
||||||
|
})
|
||||||
|
|
||||||
it('warn invalid watch source', () => {
|
it('warn invalid watch source', () => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
watch(1, () => {})
|
watch(1, () => {})
|
||||||
expect(`Invalid watch source`).toHaveBeenWarned()
|
expect(`Invalid watch source`).toHaveBeenWarned()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('warn invalid watch source: multiple sources', () => {
|
||||||
|
watch([1], () => {})
|
||||||
|
expect(`Invalid watch source`).toHaveBeenWarned()
|
||||||
|
})
|
||||||
|
|
||||||
it('stopping the watcher (effect)', async () => {
|
it('stopping the watcher (effect)', async () => {
|
||||||
const state = reactive({ count: 0 })
|
const state = reactive({ count: 0 })
|
||||||
let dummy
|
let dummy
|
||||||
|
@ -44,13 +44,17 @@ export type WatchCallback<V = any, OV = any> = (
|
|||||||
) => any
|
) => any
|
||||||
|
|
||||||
type MapSources<T> = {
|
type MapSources<T> = {
|
||||||
[K in keyof T]: T[K] extends WatchSource<infer V> ? V : never
|
[K in keyof T]: T[K] extends WatchSource<infer V>
|
||||||
|
? V
|
||||||
|
: T[K] extends object ? T[K] : never
|
||||||
}
|
}
|
||||||
|
|
||||||
type MapOldSources<T, Immediate> = {
|
type MapOldSources<T, Immediate> = {
|
||||||
[K in keyof T]: T[K] extends WatchSource<infer V>
|
[K in keyof T]: T[K] extends WatchSource<infer V>
|
||||||
? Immediate extends true ? (V | undefined) : V
|
? Immediate extends true ? (V | undefined) : V
|
||||||
: never
|
: T[K] extends object
|
||||||
|
? Immediate extends true ? (T[K] | undefined) : T[K]
|
||||||
|
: never
|
||||||
}
|
}
|
||||||
|
|
||||||
type InvalidateCbRegistrator = (cb: () => void) => void
|
type InvalidateCbRegistrator = (cb: () => void) => void
|
||||||
@ -86,7 +90,7 @@ const INITIAL_WATCHER_VALUE = {}
|
|||||||
// on position in the source array. Otherwise the values will get a union type
|
// on position in the source array. Otherwise the values will get a union type
|
||||||
// of all possible value types.
|
// of all possible value types.
|
||||||
export function watch<
|
export function watch<
|
||||||
T extends Readonly<WatchSource<unknown>[]>,
|
T extends Readonly<Array<WatchSource<unknown> | object>>,
|
||||||
Immediate extends Readonly<boolean> = false
|
Immediate extends Readonly<boolean> = false
|
||||||
>(
|
>(
|
||||||
sources: T,
|
sources: T,
|
||||||
@ -147,17 +151,31 @@ function doWatch(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const warnInvalidSource = (s: unknown) => {
|
||||||
|
warn(
|
||||||
|
`Invalid watch source: `,
|
||||||
|
s,
|
||||||
|
`A watch source can only be a getter/effect function, a ref, ` +
|
||||||
|
`a reactive object, or an array of these types.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const instance = currentInstance
|
const instance = currentInstance
|
||||||
|
|
||||||
let getter: () => any
|
let getter: () => any
|
||||||
if (isArray(source)) {
|
if (isArray(source)) {
|
||||||
getter = () =>
|
getter = () =>
|
||||||
source.map(
|
source.map(s => {
|
||||||
s =>
|
if (isRef(s)) {
|
||||||
isRef(s)
|
return s.value
|
||||||
? s.value
|
} else if (isReactive(s)) {
|
||||||
: callWithErrorHandling(s, instance, ErrorCodes.WATCH_GETTER)
|
return traverse(s)
|
||||||
)
|
} else if (isFunction(s)) {
|
||||||
|
return callWithErrorHandling(s, instance, ErrorCodes.WATCH_GETTER)
|
||||||
|
} else {
|
||||||
|
__DEV__ && warnInvalidSource(s)
|
||||||
|
}
|
||||||
|
})
|
||||||
} else if (isRef(source)) {
|
} else if (isRef(source)) {
|
||||||
getter = () => source.value
|
getter = () => source.value
|
||||||
} else if (isReactive(source)) {
|
} else if (isReactive(source)) {
|
||||||
@ -187,13 +205,7 @@ function doWatch(
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
getter = NOOP
|
getter = NOOP
|
||||||
__DEV__ &&
|
__DEV__ && warnInvalidSource(source)
|
||||||
warn(
|
|
||||||
`Invalid watch source: `,
|
|
||||||
source,
|
|
||||||
`A watch source can only be a getter/effect function, a ref, ` +
|
|
||||||
`a reactive object, or an array of these types.`
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cb && deep) {
|
if (cb && deep) {
|
||||||
|
Loading…
Reference in New Issue
Block a user