0
# Lifecycle and Events
1
2
Decorators for handling component lifecycle events and custom event emission. These decorators provide reactive data observation and automatic event emission patterns for Vue class-based components.
3
4
## Capabilities
5
6
### Watch Decorator
7
8
Creates reactive watchers for data properties, enabling components to respond to changes in data, props, or computed properties.
9
10
```typescript { .api }
11
/**
12
* Creates reactive watchers for data properties
13
* @param path - Property path or expression to observe (required)
14
* @param options - WatchOptions object (optional, defaults to {})
15
* @returns Method decorator function
16
*/
17
function Watch(path: string, options: WatchOptions = {}): MethodDecorator;
18
19
interface WatchOptions {
20
deep?: boolean;
21
immediate?: boolean;
22
}
23
```
24
25
**Usage Examples:**
26
27
```typescript
28
import { Vue, Component, Watch, Prop } from "vue-property-decorator";
29
30
@Component
31
export default class MyComponent extends Vue {
32
@Prop()
33
count!: number;
34
35
localData = 0;
36
user = { name: "", age: 0 };
37
38
// Basic watcher
39
@Watch("count")
40
onCountChanged(newVal: number, oldVal: number) {
41
console.log(`count changed from ${oldVal} to ${newVal}`);
42
}
43
44
// Deep watcher for objects
45
@Watch("user", { deep: true })
46
onUserChanged(newUser: any, oldUser: any) {
47
console.log("User object changed:", newUser);
48
}
49
50
// Immediate watcher (executes on component creation)
51
@Watch("localData", { immediate: true })
52
onLocalDataChanged(newVal: number, oldVal: number) {
53
if (newVal > 10) {
54
this.$emit("threshold-exceeded", newVal);
55
}
56
}
57
58
// Watch nested properties
59
@Watch("user.name")
60
onUserNameChanged(newName: string, oldName: string) {
61
console.log(`User name changed from ${oldName} to ${newName}`);
62
}
63
64
// Watch computed properties
65
get fullName() {
66
return `${this.user.name} (${this.user.age})`;
67
}
68
69
@Watch("fullName")
70
onFullNameChanged(newFullName: string) {
71
console.log("Full name updated:", newFullName);
72
}
73
}
74
```
75
76
### Emit Decorator
77
78
Automatically emits events with method return values and arguments, providing a declarative way to handle component event emission.
79
80
```typescript { .api }
81
/**
82
* Automatically emits events with method return values and arguments
83
* @param event - Event name (optional, defaults to kebab-case method name)
84
* @returns Method decorator function
85
*/
86
function Emit(event?: string): MethodDecorator;
87
```
88
89
**Usage Examples:**
90
91
```typescript
92
import { Vue, Component, Emit } from "vue-property-decorator";
93
94
@Component
95
export default class MyComponent extends Vue {
96
count = 0;
97
98
// Basic emit - event name defaults to kebab-case method name
99
@Emit()
100
increment() {
101
this.count++;
102
return this.count; // Emitted as first argument
103
}
104
105
// Custom event name
106
@Emit("custom-event")
107
handleCustomAction() {
108
return { timestamp: Date.now(), action: "custom" };
109
}
110
111
// Emit with method arguments
112
@Emit("user-updated")
113
updateUser(name: string, age: number) {
114
// Method arguments are emitted after return value
115
return { success: true }; // Emitted as [{ success: true }, "name", age]
116
}
117
118
// Emit without return value
119
@Emit("button-clicked")
120
handleClick() {
121
// No return value, only method arguments are emitted
122
console.log("Button was clicked");
123
}
124
125
// Emit with Promise return value
126
@Emit("async-complete")
127
async performAsyncAction() {
128
const result = await this.fetchData();
129
return result; // Promise result is awaited and then emitted
130
}
131
132
// Complex emit with multiple arguments
133
@Emit("data-processed")
134
processData(input: any[], options: any) {
135
const processed = input.map(item => ({ ...item, processed: true }));
136
return {
137
processed,
138
originalCount: input.length,
139
processedCount: processed.length
140
};
141
// Emits: [returnValue, input, options]
142
}
143
144
private async fetchData() {
145
// Simulate async operation
146
return new Promise(resolve => {
147
setTimeout(() => resolve({ data: "fetched" }), 1000);
148
});
149
}
150
}
151
```
152
153
## Advanced Usage Patterns
154
155
### Form Validation with Watchers
156
157
```typescript
158
import { Vue, Component, Watch, Prop } from "vue-property-decorator";
159
160
@Component
161
export default class ValidationForm extends Vue {
162
@Prop({ required: true })
163
initialData!: any;
164
165
formData = {
166
email: "",
167
password: "",
168
confirmPassword: ""
169
};
170
171
errors: any = {};
172
173
@Watch("formData.email")
174
validateEmail(email: string) {
175
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
176
this.errors.email = emailRegex.test(email) ? null : "Invalid email format";
177
}
178
179
@Watch("formData.password")
180
validatePassword(password: string) {
181
this.errors.password = password.length >= 8 ? null : "Password must be at least 8 characters";
182
// Re-validate confirm password when password changes
183
this.validateConfirmPassword(this.formData.confirmPassword);
184
}
185
186
@Watch("formData.confirmPassword")
187
validateConfirmPassword(confirmPassword: string) {
188
this.errors.confirmPassword =
189
confirmPassword === this.formData.password ? null : "Passwords do not match";
190
}
191
192
@Watch("initialData", { immediate: true, deep: true })
193
loadInitialData(data: any) {
194
if (data) {
195
this.formData = { ...data };
196
}
197
}
198
}
199
```
200
201
### Event Chain with Emit
202
203
```typescript
204
import { Vue, Component, Emit, Watch } from "vue-property-decorator";
205
206
@Component
207
export default class DataProcessor extends Vue {
208
rawData: any[] = [];
209
processing = false;
210
211
@Watch("rawData")
212
onDataChanged(newData: any[]) {
213
if (newData.length > 0) {
214
this.startProcessing();
215
}
216
}
217
218
@Emit("processing-started")
219
startProcessing() {
220
this.processing = true;
221
return { timestamp: Date.now(), itemCount: this.rawData.length };
222
}
223
224
@Emit("item-processed")
225
processItem(item: any, index: number) {
226
// Simulate processing
227
const processed = { ...item, processed: true, index };
228
return processed;
229
}
230
231
@Emit("processing-complete")
232
completeProcessing() {
233
this.processing = false;
234
return {
235
timestamp: Date.now(),
236
totalProcessed: this.rawData.length,
237
success: true
238
};
239
}
240
241
@Emit("processing-error")
242
handleProcessingError(error: Error) {
243
this.processing = false;
244
return { error: error.message, timestamp: Date.now() };
245
}
246
}
247
```
248
249
### Real-time Data Synchronization
250
251
```typescript
252
import { Vue, Component, Watch, Emit } from "vue-property-decorator";
253
254
@Component
255
export default class RealTimeSync extends Vue {
256
localData: any = {};
257
syncEnabled = true;
258
lastSyncTime = 0;
259
260
@Watch("localData", { deep: true })
261
onLocalDataChanged(newData: any, oldData: any) {
262
if (this.syncEnabled && this.hasSignificantChanges(newData, oldData)) {
263
this.scheduleSync();
264
}
265
}
266
267
@Watch("syncEnabled")
268
onSyncToggled(enabled: boolean) {
269
if (enabled) {
270
this.performSync();
271
}
272
}
273
274
@Emit("sync-requested")
275
scheduleSync() {
276
// Debounce sync requests
277
clearTimeout(this.syncTimer);
278
this.syncTimer = setTimeout(() => {
279
this.performSync();
280
}, 1000);
281
return { data: this.localData, scheduled: true };
282
}
283
284
@Emit("sync-complete")
285
async performSync() {
286
try {
287
await this.syncToServer(this.localData);
288
this.lastSyncTime = Date.now();
289
return { success: true, timestamp: this.lastSyncTime };
290
} catch (error) {
291
this.handleSyncError(error);
292
}
293
}
294
295
@Emit("sync-error")
296
handleSyncError(error: any) {
297
return { error: error.message, timestamp: Date.now() };
298
}
299
300
private syncTimer: any;
301
302
private hasSignificantChanges(newData: any, oldData: any): boolean {
303
// Implementation for determining significant changes
304
return JSON.stringify(newData) !== JSON.stringify(oldData);
305
}
306
307
private async syncToServer(data: any): Promise<void> {
308
// Implementation for server synchronization
309
return new Promise((resolve) => {
310
setTimeout(resolve, 500); // Simulate network delay
311
});
312
}
313
}
314
```
315
316
## Types
317
318
```typescript { .api }
319
interface WatchOptions {
320
deep?: boolean;
321
immediate?: boolean;
322
}
323
324
type MethodDecorator = (target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor) => void;
325
```