|
1 | 1 | import { ComponentInstance } from '../component'
|
2 | 2 | import { Ref, isRef, isReactive } from '../reactivity'
|
3 |
| -import { assert, logError, noopFn, warn, isFunction } from '../utils' |
| 3 | +import { |
| 4 | + assert, |
| 5 | + logError, |
| 6 | + noopFn, |
| 7 | + warn, |
| 8 | + isFunction, |
| 9 | + isObject, |
| 10 | + isArray, |
| 11 | + isPlainObject, |
| 12 | + isSet, |
| 13 | + isMap, |
| 14 | +} from '../utils' |
4 | 15 | import { defineComponentInstance } from '../utils/helper'
|
5 | 16 | import { getCurrentInstance, getVueConstructor } from '../runtimeContext'
|
6 | 17 | import {
|
@@ -272,13 +283,29 @@ function createWatcher(
|
272 | 283 | let deep = options.deep
|
273 | 284 |
|
274 | 285 | let getter: () => any
|
275 |
| - if (Array.isArray(source)) { |
276 |
| - getter = () => source.map((s) => (isRef(s) ? s.value : s())) |
277 |
| - } else if (isRef(source)) { |
| 286 | + if (isRef(source)) { |
278 | 287 | getter = () => source.value
|
279 | 288 | } else if (isReactive(source)) {
|
280 | 289 | getter = () => source
|
281 | 290 | deep = true
|
| 291 | + } else if (isArray(source)) { |
| 292 | + getter = () => |
| 293 | + source.map((s) => { |
| 294 | + if (isRef(s)) { |
| 295 | + return s.value |
| 296 | + } else if (isReactive(s)) { |
| 297 | + return traverse(s) |
| 298 | + } else if (isFunction(s)) { |
| 299 | + return s() |
| 300 | + } else { |
| 301 | + warn( |
| 302 | + `Invalid watch source: ${JSON.stringify(s)}. |
| 303 | + A watch source can only be a getter/effect function, a ref, a reactive object, or an array of these types.`, |
| 304 | + vm |
| 305 | + ) |
| 306 | + return noopFn |
| 307 | + } |
| 308 | + }) |
282 | 309 | } else if (isFunction(source)) {
|
283 | 310 | getter = source as () => any
|
284 | 311 | } else {
|
@@ -405,3 +432,26 @@ export function watch<T = any>(
|
405 | 432 |
|
406 | 433 | return createWatcher(vm, source, callback, opts)
|
407 | 434 | }
|
| 435 | + |
| 436 | +function traverse(value: unknown, seen: Set<unknown> = new Set()) { |
| 437 | + if (!isObject(value) || seen.has(value)) { |
| 438 | + return value |
| 439 | + } |
| 440 | + seen.add(value) |
| 441 | + if (isRef(value)) { |
| 442 | + traverse(value.value, seen) |
| 443 | + } else if (isArray(value)) { |
| 444 | + for (let i = 0; i < value.length; i++) { |
| 445 | + traverse(value[i], seen) |
| 446 | + } |
| 447 | + } else if (isSet(value) || isMap(value)) { |
| 448 | + value.forEach((v: any) => { |
| 449 | + traverse(v, seen) |
| 450 | + }) |
| 451 | + } else if (isPlainObject(value)) { |
| 452 | + for (const key in value) { |
| 453 | + traverse((value as any)[key], seen) |
| 454 | + } |
| 455 | + } |
| 456 | + return value |
| 457 | +} |
0 commit comments