Skip to content

[XYZ] [Angular 2] Lifecycle Component

trangnt58 edited this page Oct 24, 2016 · 4 revisions

#Mục lục

  1. [Định nghĩa component] (#whatiscomponent)
  2. [Vòng đời component] (#vongdoicomponent)
  3. [Component lifecycle hooks] (#hooks)
  4. [Lifecycle sequence] (#sequence)
  5. [Cách dùng] (#use)
  6. [Thực hành với lifecycle] (#practice)
## Định nghĩa component - Mỗi ứng dụng được cấu trúc như một cây component. Mỗi nút bao gồm các thành phần chính là file component và file template - Root Component là thành phần cao nhất chứa các thành phần (component) còn lại. ## Vòng đời Component - Một component có một vòng đời được quản lí bởi chính Angular. Angular tạo ra, render nó, tạo và render các con của nó, kiểm tra nó khi thuộc tính của giá trị ràng buộc thay đổi, và hủy bỏ nó trước khi xóa trên phần tử DOM. - Angular đặt ra component lifecycle hooks giúp chúng ta có cái nhìn tổng quan về các thời điểm then chốt và có hành động khi chúng xuất hiện. Bằng việc thêm các hành động vào các component lifecycle hook, ta có thể thực hiện, lặp lại các hành động khi các sự kiện tương ứng trong vòng đời của component xảy ra. ## Component lifecycle hooks - Là 'điểm neo' các mốc sự kiện quan trọng trong vòng đời của component, từ khi nó được tạo ra và hủy bỏ. - Các Component lifecycle hooks cho phép gán các hành động cụ thể sẽ được thực hiện tại thời điểm tương ứng với hook trong vòng đời của component. - Các thực thể directive và component có một vòng đời do Angular tạo ra, cập nhật và hủy bỏ chúng - Các nhà phát triển có thể thiết lập các thời điểm then chốt trong vòng đời bằng cách thực thi một hoặc nhiều Lifecycle Hook interfaces trong thư viện Angular core. ## Lifecycle sequence - Khi một component được khởi tạo, sau khi hoàn thành hàm constructor, Angular sẽ gọi đến hook **ngOnChanges**. **ngOnChanges** bắt các thay đổi của giá trị khởi tạo được truyền vào component, được lặp đi lặp lại nhiều lần trong suốt vòng đời của component. - Kết thúc **ngOnChanges**, Angular tiếp tục gọi đến **ngOnInit**. Đây là hook được gọi một lần duy nhất, ngay sau khi **ngOnChanges** đầu tiên hoàn tất. - Tiếp đó, Component tiến hành render view, truyền dữ liệu vào view, Angular gọi đến hook **ngAfterContentInit** và khi hoàn tất gọi đến hook **ngAfterContentChecked** sau khi đã kiểm tra dữ liệu lấy từ bên ngoài vào view. - Khi render view của component, Angular gọi đến **ngAfterViewInit**, sau đó gọi hook **ngAfterViewChecked** khi đã kiểm tra xong dữ liệu trên view của component - Cuối cùng, khi ta gọi đến hàm hủy của Class, Angular sẽ gọi và thực hiện các hành động trong hook **ngOnDestroy** trước khi thực hiện hàm hủy và kết thúc vòng đời của component. ## Cách dùng các component lifecycle hooks - Mỗi thực thể có một phương thức hook đơn mà tên của nó là tên của interface có tiền tố ng. Trong ví dụ, `OnInit` interface có một phương thức hook có tên là `ngOnInit`. Chúng ta phải implement nó trong class component, giống như ví dụ này:
**peek-a-boo.component.ts**
export class PeekABoo implements OnInit {
  constructor(private logger: LoggerService) { }

// implement OnInit's ngOnInit method ngOnInit() { this.logIt(OnInit); }

protected logIt(msg: string) { this.logger.log(#${nextId++} ${msg}); } }

Không có directive hoặc component nào sẽ implement tất cả chúng và chỉ một số hooks có ý nghĩa cho các component. Angular chỉ gọi một directive/component phương thức hook nếu chúng được định nghĩa

Dưới đây là một số các phương thức component lifecycle hook
Sử dụng chung cho cả Directive và Component

  • ngOnInit: Khởi tạo directive và component sau khi Angular khởi tạo các thuộc tính của dữ liệu ràng buộc
  • ngOnChanges: Phản hồi lại sau khi angular cài đặt một thuộc tính dữ liệu ràng buộc. Phương thức nhận một object changes của hiện tại và giá trị trước đó
  • ngDoCheck: Phát hiện và thực hiện thay đổi. Được gọi mỗi khi tìm thấy thay đổi
  • ngOnDestroy: Thu hồi trước khi Angular hủy bỏ directive/component. Hủy đăng ký observables và tháo gỡ các sự kiện để tránh tốn bộ nhớ

Chỉ với Component

  • ngAfterContentInit: Sau khi angular xuất content ra view
  • ngAfterContentChecked: Sau khi Angular kiểm tra sự ràng buộc content để xuất content ra view
  • ngAfterViewInit: Sau khi Angular tạo ra view của componet
  • ngAfterViewChecked: Sau khi Angular kiểm tra ràng buộc dữ liệu trên view
Lưu ý: Constructor và OnInit
  • Constructor là phương thức khởi tạo mặc định của class, thực hiện khi class được khởi tạo.
  • NgOnInit là một hook vòng đời, được gọi bởi Angular2 để chỉ rõ Angular đã hoàn thành việc tạo ra component.
  • Không nên lấy dữ liệu về khi khởi tạo bởi constructor theo khuyến cáo lập trình thì càng gọn nhẹ càng tốt. Vì vậy, nên sử dụng NgOnInit để lấy dữ liệu vào component ngay sau khi khởi tạo
## Thực hành với lifecycle - Example: [https://angular.io/resources/live-examples/lifecycle-hooks/ts/plnkr.html](https://angular.io/resources/live-examples/lifecycle-hooks/ts/plnkr.html) - Đọc thêm tại đây: [https://angular.io/docs/ts/latest/guide/lifecycle-hooks.html](https://angular.io/docs/ts/latest/guide/lifecycle-hooks.html)

Ví dụ dưới đây giải thích các thức hoạt động của các lifecycle hooks thông qua một series các ví dụ được biểu diễn bằng các components dưới sự điều khiển của App Component.

Dưới đây là mô tả ngắn gọn cho các ví dụ nhỏ:

Component Description
Peek-a-book Giải thích từng lifecycle hook. Mỗi phương thức hook được in ra trên màn hình
Spy Các directives cũng có các lifecycle hook. SpyDirective thể hiện khi các phần tử spies được tạo ra hoặc hủy bỏ, bằng cách sử dụng ngOnInitngOnDestroy. Ví dụ này áp dụng SpyDirective cho thẻ div trong ngFor khi lặp các hero bởi SpyComponent
OnChanges Hiểu cách Angular gọi ngOnChanges hook với một changes object mỗi khi một thuộc tính đầu vào của component thay đổi.
Do Check Thực hiện phương thức ngDoCheck khi phát hiện thay đổi. Hiểu cách Angular gọi hook này và xem nó thực hiện thay đổi
AfterView Thể hiện cách Angular định nghĩa một view. Giải thích phương thức ngAfterViewInitngAfterViewChecked
AfterContent Thể hiện cách ánh xạ content ra một component và cách phân biệt các content được ánh xạ từ các view con. Giải thích phương thức ngAfterContentInitngAfterContentChecked
Counter Giải thích sự tổ hợp của một component và một directive và từng hooks của nó. Trong ví du này, CounterComponent hiển thị sự thay đổi mỗi khi component cha tăng thuộc tính đầu vào. Trong lúc đó, SpyDirective sẽ được thực hiện để CounterComponet thấy nơi nó đi vào, được khởi tạo và hủy bỏ.

Peek-a-boo: tất cả các hook

PeekABooComponent thể hiện tất các các hooks trong một component. Nó thể hiện cách Angular gọi các hooks được sắp xếp theo thứ tự.
Ảnh dưới thể hiện các trạng thái màn hình sau khi người dùng nhấn vào nút Create và sau đó nhấn vào nút Destroy.

peek

Dãy các thông điệp trả lại màn hình sẽ theo thứ tự OnChanges, OnInit, DoCheck (3x), AfterContentInit, AfterContentChecked (3x), AfterViewInit, AfterViewChecked (3x), and OnDestroy.

Giải thích các hooks thường dùng

Spying OnInit and OnDestroy

Spy directive này rất đơn giản, nó giải thích cho ngOnInitngOnDestroy, nó in ra thông điệp đến directive cha là LoggerService

// Spy on any element to which it is applied.
// Usage: <div mySpy>...</div>
@Directive({selector: '[mySpy]'})
export class SpyDirective implements OnInit, OnDestroy {

  constructor(private logger: LoggerService) { }

  ngOnInit()    { this.logIt(`onInit`); }

  ngOnDestroy() { this.logIt(`onDestroy`); }

  private logIt(msg: string) {
    this.logger.log(`Spy #${nextId++} ${msg}`);
  }
}

Bạn có thể áp dụng spy cho các phần tử của component và nó sẽ khởi tạo và hủy bỏ cùng với thời gian giống phần tử được áp dụng. Dưới đây là sự áp dụng cho vòng lặp hero trong thẻ <div>

<div *ngFor="let hero of heroes" mySpy class="heroes">
  {{hero}}
</div>

Mỗi spy khởi tạo và hủy bỏ đánh dấu sự sinh ra và biến mất của các thẻ <div> hero gắn với nó spy

OnInit

Sử dụng ngOnInit với 2 mục đích chính:

  1. để biểu diễn một sự khởi tạo phức tạp sau construction
  2. để cài đặt cho một component sau khi Angular cài các biến đầu vào

Các component nên đơn giản và an toàn để xây dựng. Vì vậy, không nên kết nối dữ liệu ở constructor của component. Phương thức ngOnInit là nơi lí tưởng cho của việc lấy dữ liệu cho một component.

OnDestroy

Đặt các phương thức logic trong ngOnDestroy, các logic này sẽ phải chạy trước khi Angular hủy bỏ directive.

Đây là nơi để giải phóng các tài nguyên không được tự động hủy bỏ như hủy đăng kí từ observables và các sự kiện của phần tử DOM, dừng các thời gian interval, hủy đăng kí tất cả các callback. Nếu dử dụng nó, bạn sẽ tránh bị rơi vào trường hợp tràn bộ nhớ

OnChanges

Angular gọi phương thức ngOnChange mỗi khi nó phát hiện thay đổi thuộc tính đầu vào của component hoặc directive. Dưới đây là một onChanges

ngOnChanges(changes: {[propertyName: string]: SimpleChange}) {
  for (let propName in changes) {
    let chng = changes[propName];
    let cur  = JSON.stringify(chng.currentValue);
    let prev = JSON.stringify(chng.previousValue);
    this.changeLog.push(`${propName}: currentValue = ${cur}, previousValue = ${prev}`);
  }
}

Phương thức ngOnChanges lấy đối tượng để nối khi mỗi thuộc tính name thay đổi với đối tượng SimpleChange nắm giữ giá trị hiện tại và giá trị trước đó. Hooks này sẽ lặp đi lặp lại mỗi khi các thuộc tính thay đổi và in chúng ra màn hình.
Ví dụ như OnChangesComponent có 2 thuộc tính đầu vào heropower

@Input() hero: Hero;
@Input() power: string;

Cha của nó OnChangesParentComponent kết nối với nó như sau:

<on-changes [hero]="hero" [power]="power"></on-changes>

Đây là ví dụ khi người dùng tạo các sự thay đổi:
onChanges

Các dòng log xuất hiện khi giá trị của thuộc tính power thay đổi. Nhưng ngOnChanges không bắt sự thay đổi của hero.name. Đây là một điều khá bất ngờ.
Angular chỉ gọi hook khi giá trị của thuộc tính đầu vào thay đổi. Giá trị của thuộc tính hero là tham chiếu của đối tượng hero. Angular không quan tâm khi thuộc tính name của hero thay đổi. Đối tượng 'hero' tham chiếu không thay đổi, vì vậy, sẽ không có sự thay đổi nào được in ra