0
# Watch & Effects
1
2
Vue's watch system enables reactive observation of data changes with flexible scheduling and deep/shallow watching options. Effects provide low-level reactive behavior for custom reactivity patterns.
3
4
## Capabilities
5
6
### Watch Functions
7
8
Watch reactive data sources and execute callbacks when they change.
9
10
```typescript { .api }
11
/**
12
* Watches a single reactive source
13
* @param source - Reactive source to watch
14
* @param callback - Callback executed when source changes
15
* @param options - Watch configuration options
16
* @returns Function to stop the watcher
17
*/
18
function watch<T, Immediate extends Readonly<boolean> = false>(
19
source: WatchSource<T>,
20
callback: WatchCallback<T, Immediate extends true ? T | undefined : T>,
21
options?: WatchOptions<T, Immediate>
22
): WatchHandle;
23
24
/**
25
* Watches multiple reactive sources
26
* @param sources - Array of reactive sources to watch
27
* @param callback - Callback executed when any source changes
28
* @param options - Watch configuration options
29
* @returns Function to stop the watcher
30
*/
31
function watch<T extends MultiWatchSources, Immediate extends Readonly<boolean> = false>(
32
sources: [...T],
33
callback: WatchCallback<MapSources<T>, Immediate extends true ? Partial<MapSources<T>> : MapSources<T>>,
34
options?: WatchOptions<T, Immediate>
35
): WatchHandle;
36
37
/**
38
* Watches an object and its properties
39
* @param source - Object to watch
40
* @param callback - Callback executed when object changes
41
* @param options - Watch configuration options
42
* @returns Function to stop the watcher
43
*/
44
function watch<T extends object, Immediate extends Readonly<boolean> = false>(
45
source: T,
46
callback: WatchCallback<T, Immediate extends true ? T | undefined : T>,
47
options?: WatchOptions<T, Immediate>
48
): WatchHandle;
49
```
50
51
**Usage Examples:**
52
53
```typescript
54
import { ref, reactive, watch } from "@vue/runtime-core";
55
56
const count = ref(0);
57
const state = reactive({ name: "Vue", version: 3 });
58
59
// Watch a ref
60
const stopWatchingCount = watch(count, (newValue, oldValue) => {
61
console.log(`Count changed from ${oldValue} to ${newValue}`);
62
});
63
64
// Watch multiple sources
65
const stopWatchingMultiple = watch(
66
[count, () => state.name],
67
([newCount, newName], [oldCount, oldName]) => {
68
console.log(`Count: ${oldCount} -> ${newCount}`);
69
console.log(`Name: ${oldName} -> ${newName}`);
70
}
71
);
72
73
// Watch with immediate execution
74
watch(
75
() => state.version,
76
(version) => {
77
console.log(`Version: ${version}`);
78
},
79
{ immediate: true } // Runs immediately with current value
80
);
81
82
// Deep watch for objects
83
watch(
84
state,
85
(newState, oldState) => {
86
console.log("State changed:", newState);
87
},
88
{ deep: true } // Watches nested properties
89
);
90
91
// Cleanup
92
stopWatchingCount();
93
stopWatchingMultiple();
94
```
95
96
### WatchEffect Functions
97
98
Automatically track dependencies and re-run when they change.
99
100
```typescript { .api }
101
/**
102
* Runs a function immediately and re-runs when dependencies change
103
* @param effect - Function to run and track dependencies
104
* @param options - Effect configuration options
105
* @returns Function to stop the effect
106
*/
107
function watchEffect(
108
effect: WatchEffect,
109
options?: WatchEffectOptions
110
): WatchStopHandle;
111
112
/**
113
* Like watchEffect but runs after component updates (post-flush)
114
* @param effect - Function to run and track dependencies
115
* @param options - Effect configuration options
116
* @returns Function to stop the effect
117
*/
118
function watchPostEffect(
119
effect: WatchEffect,
120
options?: WatchEffectOptions
121
): WatchStopHandle;
122
123
/**
124
* Like watchEffect but runs synchronously
125
* @param effect - Function to run and track dependencies
126
* @param options - Effect configuration options
127
* @returns Function to stop the effect
128
*/
129
function watchSyncEffect(
130
effect: WatchEffect,
131
options?: WatchEffectOptions
132
): WatchStopHandle;
133
```
134
135
**Usage Examples:**
136
137
```typescript
138
import { ref, watchEffect, watchPostEffect, watchSyncEffect } from "@vue/runtime-core";
139
140
const count = ref(0);
141
const name = ref("Vue");
142
143
// Basic watchEffect
144
const stopEffect = watchEffect(() => {
145
console.log(`Count is ${count.value} and name is ${name.value}`);
146
});
147
// Runs immediately and when count or name changes
148
149
// watchEffect with cleanup
150
watchEffect((onInvalidate) => {
151
const timer = setInterval(() => {
152
console.log(`Timer: ${count.value}`);
153
}, 1000);
154
155
// Cleanup when effect is invalidated
156
onInvalidate(() => {
157
clearInterval(timer);
158
});
159
});
160
161
// Post-flush effect (runs after DOM updates)
162
watchPostEffect(() => {
163
// This runs after component DOM updates
164
console.log("DOM updated, count is:", count.value);
165
});
166
167
// Sync effect (runs synchronously)
168
watchSyncEffect(() => {
169
console.log("Sync effect, count:", count.value);
170
});
171
172
// Stop effects
173
stopEffect();
174
```
175
176
### Watch Options & Configuration
177
178
Configure watch behavior with various options.
179
180
```typescript { .api }
181
interface WatchOptions<T = any, Immediate extends boolean = boolean> {
182
/**
183
* Run the callback immediately with current value
184
*/
185
immediate?: Immediate;
186
187
/**
188
* Watch nested properties in objects and arrays
189
*/
190
deep?: boolean;
191
192
/**
193
* Flush timing: 'pre' (before updates), 'post' (after updates), 'sync' (synchronous)
194
*/
195
flush?: 'pre' | 'post' | 'sync';
196
197
/**
198
* Debug hook called when watcher triggers
199
*/
200
onTrack?: (event: DebuggerEvent) => void;
201
202
/**
203
* Debug hook called when watcher triggers
204
*/
205
onTrigger?: (event: DebuggerEvent) => void;
206
207
/**
208
* Indicates whether the job is allowed to recursively trigger itself
209
*/
210
allowRecurse?: boolean;
211
}
212
213
interface WatchEffectOptions {
214
/**
215
* Flush timing for the effect
216
*/
217
flush?: 'pre' | 'post' | 'sync';
218
219
/**
220
* Debug hook called when effect is tracked
221
*/
222
onTrack?: (event: DebuggerEvent) => void;
223
224
/**
225
* Debug hook called when effect is triggered
226
*/
227
onTrigger?: (event: DebuggerEvent) => void;
228
229
/**
230
* Indicates whether the job is allowed to recursively trigger itself
231
*/
232
allowRecurse?: boolean;
233
}
234
```
235
236
**Usage Examples:**
237
238
```typescript
239
import { ref, reactive, watch, watchEffect } from "@vue/runtime-core";
240
241
const user = reactive({
242
profile: {
243
name: "Alice",
244
settings: {
245
theme: "dark"
246
}
247
}
248
});
249
250
// Deep watching
251
watch(
252
user,
253
(newUser, oldUser) => {
254
console.log("User changed:", newUser);
255
},
256
{
257
deep: true, // Watch nested properties
258
immediate: true, // Run immediately
259
flush: 'post' // Run after DOM updates
260
}
261
);
262
263
// Flush timing examples
264
const count = ref(0);
265
266
// Pre-flush (default) - runs before DOM updates
267
watch(count, () => console.log("Pre-flush"), { flush: 'pre' });
268
269
// Post-flush - runs after DOM updates
270
watch(count, () => console.log("Post-flush"), { flush: 'post' });
271
272
// Sync - runs synchronously
273
watch(count, () => console.log("Sync"), { flush: 'sync' });
274
275
// Debug hooks
276
watchEffect(
277
() => {
278
console.log("Count:", count.value);
279
},
280
{
281
onTrack(e) {
282
console.log("Tracked:", e);
283
},
284
onTrigger(e) {
285
console.log("Triggered:", e);
286
}
287
}
288
);
289
```
290
291
## Types
292
293
```typescript { .api }
294
type WatchSource<T = any> = Ref<T> | ComputedRef<T> | (() => T);
295
296
type MultiWatchSources = (WatchSource<unknown> | object)[];
297
298
type MapSources<T> = {
299
[K in keyof T]: T[K] extends WatchSource<infer V>
300
? V
301
: T[K] extends object
302
? T[K]
303
: never;
304
};
305
306
type WatchCallback<V = any, OV = any> = (
307
value: V,
308
oldValue: OV,
309
onCleanup: OnCleanup
310
) => any;
311
312
type WatchStopHandle = () => void;
313
314
type WatchHandle = WatchStopHandle;
315
316
interface WatchEffect {
317
(onCleanup: OnCleanup): void;
318
}
319
320
type OnCleanup = (cleanupFn: () => void) => void;
321
322
interface DebuggerEvent {
323
effect: ReactiveEffect;
324
target: object;
325
type: TrackOpTypes | TriggerOpTypes;
326
key: any;
327
newValue?: any;
328
oldValue?: any;
329
oldTarget?: Map<any, any> | Set<any>;
330
}
331
332
enum TrackOpTypes {
333
GET = 'get',
334
HAS = 'has',
335
ITERATE = 'iterate'
336
}
337
338
enum TriggerOpTypes {
339
SET = 'set',
340
ADD = 'add',
341
DELETE = 'delete',
342
CLEAR = 'clear'
343
}
344
```