前言
在 Angular 中,每個 Component 和 Directive 都有生命週期,由一系列的生命週期 Hook 所組成。理解這些生命週期鉤子函數,可以讓你在適當的時機執行特定的邏輯。
LifeCycle Hook Function
LifeCycle Hook Function 讓開發者在 Component 和 Directive 的不同階段進行操作。
Angular LifeCycle Hook
constructor:ES6 提供給 class 的建構子,並不屬於 AngularngOnChanges:當 Component 的一個輸入屬性發生變化時調用ngOnInit:當 Component 初始化完成時調用,此時 Component 的輸入屬性和輸出屬性都已經確定ngDoCheck:當 Angular 檢查 Component 的變化時調用,通常是由於輸入屬性發生變化或因為事件觸發引起的ngAfterContentInit:當 Component 的 Content 完成初始化之後調用,通常用於對 Component 的 Content 執行操作ngAfterContentChecked:當 Angular 檢查 Component 的 Content 發生變化時調用ngAfterViewInit:當 Component 的 View 完成初始化之後調用,通常用於對 Component 的 View 執行操作ngAfterViewChecked:當 Angular 檢查 Component 的 View 發生變化時調用ngOnDestroy:當 Component 被摧毀時調用,通常用於釋放 Component 所占用的資源
生命週期執行順序
完整的生命週期執行順序如下:
- constructor:建立 Component 實例
- ngOnChanges:輸入屬性變更時(首次也會執行)
- ngOnInit:Component 初始化完成
- ngDoCheck:變更檢測
- ngAfterContentInit:外部內容初始化完成
- ngAfterContentChecked:外部內容變更檢測
- ngAfterViewInit:視圖初始化完成
- ngAfterViewChecked:視圖變更檢測
- ngOnDestroy:Component 銷毀前
常用生命週期範例
ngOnInit
最常使用的生命週期 Hook,通常用於初始化資料。
export class UserComponent implements OnInit {
users: User[] = [];
constructor(private userService: UserService) {}
ngOnInit(): void {
// 在這裡初始化資料
this.loadUsers();
}
loadUsers(): void {
this.userService.getUsers().subscribe((users) => (this.users = users));
}
}
ngOnChanges
當 @Input() 屬性值改變時觸發。
export class ChildComponent implements OnChanges {
@Input() data: string;
ngOnChanges(changes: SimpleChanges): void {
console.log("Previous value:", changes["data"].previousValue);
console.log("Current value:", changes["data"].currentValue);
}
}
ngOnDestroy
Component 銷毀前執行,通常用於清理資源、取消訂閱。
export class MyComponent implements OnInit, OnDestroy {
private subscription: Subscription;
ngOnInit(): void {
this.subscription = this.dataService
.getData()
.subscribe((data) => console.log(data));
}
ngOnDestroy(): void {
// 取消訂閱,避免記憶體洩漏
if (this.subscription) {
this.subscription.unsubscribe();
}
}
}
ngAfterViewInit
視圖初始化完成後執行,可以安全地訪問 DOM 元素。
export class MyComponent implements AfterViewInit {
@ViewChild("myInput") myInput: ElementRef;
ngAfterViewInit(): void {
// 這時可以安全地訪問 DOM 元素
this.myInput.nativeElement.focus();
}
}
constructor vs ngOnInit
很多人會疑惑:什麼時候用 constructor,什麼時候用 ngOnInit?
constructor
- ES6 的 class 建構子
- 用於依賴注入(Dependency Injection)
- 此時 Component 的屬性可能還未初始化
- 不應該在這裡執行複雜的邏輯或 HTTP 請求
constructor(
private userService: UserService,
private router: Router
) {
// 只做簡單的初始化
console.log('Component created');
}
ngOnInit
- Angular 的生命週期 Hook
- Component 的輸入屬性已經初始化完成
- 應該在這裡執行資料載入、訂閱等操作
ngOnInit(): void {
// 執行資料初始化
this.loadData();
}
實用技巧
1. 使用 OnPush 策略優化效能
搭配 ngOnChanges 使用 ChangeDetectionStrategy.OnPush 可以提升效能。
@Component({
selector: "app-my-component",
templateUrl: "./my-component.component.html",
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MyComponent implements OnChanges {
@Input() data: any;
ngOnChanges(changes: SimpleChanges): void {
// 只有當 input 改變時才會觸發變更檢測
}
}
2. 避免在 ngDoCheck 中執行繁重操作
ngDoCheck 會在每次變更檢測時執行,頻率非常高,應避免執行繁重的操作。
3. 記得取消訂閱
在 ngOnDestroy 中取消所有訂閱,避免記憶體洩漏。
private destroy$ = new Subject<void>();
ngOnInit(): void {
this.dataService.getData()
.pipe(takeUntil(this.destroy$))
.subscribe(data => console.log(data));
}
ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
}
總結
理解 Angular 的生命週期 Hook 是開發 Angular 應用的關鍵:
- ngOnInit:最常用,用於初始化資料
- ngOnChanges:監聽 Input 屬性變化
- ngOnDestroy:清理資源,避免記憶體洩漏
- ngAfterViewInit:訪問 DOM 元素
- constructor vs ngOnInit:constructor 用於依賴注入,ngOnInit 用於資料初始化
掌握這些生命週期 Hook 的執行順序和調用時機,能夠更好地理解 Angular 中 Component 和 Directive 的運行機制,寫出更高效且穩定的應用程式。