1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| import { ReactiveEffect } from './effect'; import { isFunction, isObject } from '@vue/shared'; import { isReactive } from './reactive'; import { isRef } from './ref';
export function watch(source, cb, options = {} as any) { return doWatch(source, cb, options); }
function traverse(source, depth, currentDepth = 0, seen = new Set()) { if (!isObject(source)) { return source; }
if (depth) { if (depth <= currentDepth) { return source; } currentDepth++; }
if (seen.has(source)) { return source; }
for (const key in source) { traverse(source[key], depth, currentDepth, seen); }
return source; }
function doWatch(source, cb, { deep, immediate }) { const reactiveGetter = (source) => traverse(source, deep === false ? 1 : undefined);
let getter; if (isReactive(source)) { getter = () => reactiveGetter(source); } else if (isRef(source)) { getter = () => source.value; } else if (isFunction(source)) { getter = source; }
let oldValue; const job = () => { const newValue = effect.run(); cb(newValue, oldValue); oldValue = newValue; };
const effect = new ReactiveEffect(getter, job);
if (cb) { if (immediate) { job(); } else { oldValue = effect.run(); } } }
|