feat(watch): support directly watching reactive object in multiple sources with deep default (#1201)

This commit is contained in:
Yang Mingshan 2020-05-18 23:02:51 +08:00 committed by GitHub
parent 83b7158017
commit ba62ccd55d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 46 additions and 16 deletions

View File

@ -155,12 +155,30 @@ describe('api: watch', () => {
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', () => {
// @ts-ignore
watch(1, () => {})
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 () => {
const state = reactive({ count: 0 })
let dummy

View File

@ -44,13 +44,17 @@ export type WatchCallback<V = any, OV = any> = (
) => any
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> = {
[K in keyof T]: T[K] extends WatchSource<infer 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
@ -86,7 +90,7 @@ const INITIAL_WATCHER_VALUE = {}
// on position in the source array. Otherwise the values will get a union type
// of all possible value types.
export function watch<
T extends Readonly<WatchSource<unknown>[]>,
T extends Readonly<Array<WatchSource<unknown> | object>>,
Immediate extends Readonly<boolean> = false
>(
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
let getter: () => any
if (isArray(source)) {
getter = () =>
source.map(
s =>
isRef(s)
? s.value
: callWithErrorHandling(s, instance, ErrorCodes.WATCH_GETTER)
)
source.map(s => {
if (isRef(s)) {
return s.value
} else if (isReactive(s)) {
return traverse(s)
} else if (isFunction(s)) {
return callWithErrorHandling(s, instance, ErrorCodes.WATCH_GETTER)
} else {
__DEV__ && warnInvalidSource(s)
}
})
} else if (isRef(source)) {
getter = () => source.value
} else if (isReactive(source)) {
@ -187,13 +205,7 @@ function doWatch(
}
} else {
getter = NOOP
__DEV__ &&
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.`
)
__DEV__ && warnInvalidSource(source)
}
if (cb && deep) {