생명주기
컴포넌트와 디렉티브는 생명주기를 갖는다. 생명주기는 생성하고 소멸되기 까지의 여러 과정을 말하며 Angular 에 의해 관리된다. Angular는 생명주기를 통해 컴포넌트와 디렉티를 생성하고 렌더링하며 프로퍼티의 변화를 체크하고 DOM에서 제거하는 과정을 관리한다.
Angular의 생명주기 시퀀스와 훅 메소드
constructor
ngOnChanges
ngOninit
ngDoCheck
ngAfterContentInit
ngAfterContentChecked
ngAfterViewInit
ngAfterViewChecked
ngOnDestory
이 순서로 생명주기를 관리하고 생명주기 이름 앞에 ng 가 붙은 생명주기 훅 메소드를 제공한다.
생명주기 훅 메소드
생명주기 훅 메소드는 인터페이스 형태로 제공된다.
예를들어, onInit 생명주기에 처리되어야 할 것은 훅 메소드인 ngOnInit 에서 구현한다.ngOnInit 메소드는 OnInit 인터페이스에 포함되어 있다. 이와 같이 생명주기에는 동일한 이름의 인터페이스가 존재하며, 그 인터페이스 안에는 추상메소드가 포함된다.
1 | import { Component, OnInit } from '@angular/core'; |
컴포넌트와 디렉티브는 클래스이므로 생성자 constructor의 호출에 의해 생성된다. 그 이후 특별한 시점에 구현된 생명주기 훅 메소드를 호출한다. 모든 생명주기를 호출할 필요는 없다.
ngOnChanges
부모 컴포넌트에서 자식 컴포넌트의 입력 프로퍼티(@Input())으로 바인딩한 값이 초기화 또는 변경되었을 때 실행된다. 따라서 입력프로퍼티가 없을때는 호출하지 않는다.
1 | import { |
ngOnchanges는 ngOnit 이전에 입력 프로퍼티가 존재하는 경우 최소 1회 호출된다.
이후에는 입력 프로퍼티가 변경될 때 마다 재호출된다. 기본 자료형의 값이 재할당 되었을 때와 객체의 참조가 변경되었을 때 반응한다. 그러므로 입력프로퍼티가 아닌 일반 컴포넌트의 프로퍼티가 변경되었을 때는 반응하지 않는다.
ngOnInit
ngOnChanges 이후, 입력 프로퍼티를 포함한 모든 프로퍼티의 초기화가 완료된 시점에 한번만 호출된다.
TypeScript에서는 constructor에서 프로퍼티를 초기화하지만, angular 에서는 ngOnInit에서 초기화 처리를 하는 것이 좋다. constructor가 실행되는 시점에 angular의 입력 프로퍼티는 초기화되기 이전 상태이며 undefined가 반환된다. 반대로 ngOnInit에서는 입력 프로퍼티 참조가 보장되며 초기화가 진행된다. ngOnChanges 에서 입력 프로퍼티 초기화가 처음 수행되지만 , 입력 프로퍼티가 변경될 때마다 재호출되므로 초기화를 수행하기에는 ngOnInit 메소드가 적당하다.
ngDoCheck
ngOnInit 이후 컴포넌트 또는 디렉티브의 모든 상태 변화가 발생할 때마다 호출된다. 즉 변화 감지 로직이 실행될 때마다 호출된다.
DOM 이벤트 ,Timer 함수 이벤트, Ajax 비동기 통신 등의 처리가 수행될 때 변화 감지 로직을 실행하며 이 떄 ngDoCheck 훅 메소드가 호출된다.
ngOnChanges는 입력 프로퍼티의 값이 초기화 또는 변경 될 때만 호출되지만 ngDoCheck는 모든 상태변경에 의해 호출되므로 성능에 악영향을 미칠 수도 있다.
ngAfterContentInit
ngContent 디렉티브를 사용하여 외부 콘텐츠를 컴포넌트 뷰에 프로젝션한 이후에 호출한다. (프로젝션이란 부모 컴포넌트가 자식 컴포넌트에게 부모 컴포넌트 템플릿의 일부를 전달하는 기능을 말한다. ex) @ContentChild, @ContentChildren)
첫번째 ngDoCheck 이후에 한 번만 호출된다.
ngAfterContentChecked
콘텐츠 프로젝션에 의해 부모 컴포넌트가 전달한 부모 컴포넌트의 템플릿 조각을 체크한 후에 호출된다. ngAfterContentInit 호출 이후 , ngDoCheck가 호출된 이후에 호출된다.
ngAfterViewInit
컴포넌트의 뷰와 자식 컴포넌트의 뷰를 초기화한 이후 호출된다. 첫 번째 ngAfterContentChecked 호출 이후 한 번만 호출된다.
anAfterViewChecked
컴포넌트의 뷰와 자식 컴포넌트의 뷰를 체크한 이후 호출된다. 첫 번째 ngAfterViewInit 호출 이후 , ngAfterContentChecked 호출 이후 호출된다.
ngOnDestory
컴포넌트와 디렉티브가 소멸하기 이전 호출된다.
생명주기 예시
- 프로젝트를 생성한다. 자식 컴포넌트를 생성한다.
1 | ng new life-cycle |
- app.component.ts를 수정하여 자식 컴포넌트에 값을 전달한다.
1 | import { Component } from '@angular/core'; |
- child.component.ts를 수정하여 생성자 함수와 훅 메소드를 구현한다.
1 | |
create child 버튼을 클릭하면 자식 컴포넌트가 생성되면서 훅 메소드가 순차적으로 호출된다.
console의 호출 결과는 다음과 같다.
1 | [construnctor] |
1) 가장 먼저 constructor가 호출된다. constructor은 인스턴스 생성을 위해 호출되며 angular가 관리하는 메소드가 아니다. angular에서는 constructor에서 입력 프로퍼티 초기화가 진행되지 않으므로 prop값(입력값)이 undefined 로 출력된다.
ngOnChanges에서 입력 프로퍼티 초기화가 진행되어 부모 컴포넌트에서 전달 받은 값이 호출되므로, constructor에서 입력값을 할당하는 것은 무의미하다.
2) ngOnChanges는 자식 컴포넌트에 입력 프로퍼티가 존재하기 때문에 실행되었다. 반대로 입력 프로퍼티가 없으면 ngOnChanges가 실행되지 않는다.
3) 이후 ngOnInit, ngDoCheck, ngAfterContentInit, ngAfterContentChecked, ngAfterViewInit, ngAfterViewChecked가 순차적으로 호출된다.
4) 이후 생성된 자식 컴포넌트를 소멸시키면 ngOnDestory가 호출된다.
ngOnChanges와 ngDoCheck
ngOnChanges와 ngDoCheck는 모두 상태 변화와 관계가 있지만 차이가 있다.
ngOnChanges는 입력 프로퍼티의 참조 변경 시에 호출되고,
ngDoCheck는 모든 상태의 변화 시점, 변화감지 로직이 실행될때마다 호출된다.
하지만 객체의 경우 프로퍼티의 값을 변경하여도 객체의 참조가 변경되지 않기 때문에 ngOnChanges는 이 변화에 반응하지 않는다. 즉 immutable(불변) 한 값에만 반응한다.
- immutable(불변) : 기본 자료형이나 불변 객체처럼 생성 이후에 변경할 수 없는 값. 재할당 이외에는 참조 변경이 발생하지 않는 값
- mutable (가변) : 객체처럼 변경할 수 있는 값, 프로퍼티가 변경되어도 참조가 변경되지는 않는 값
1 | import { Component } from '@angular/core'; |
1 | import { Component, Input, OnChanges, DoCheck, SimpleChanges } from '@angular/core'; |
위 예제에서는 <기본 자료형 프로퍼티 변경> 버튼과 <객체형 프로퍼티 변경> 버튼이 두개가 있다.
1) 첫번째 기본 자료형 프로퍼티 변경 버튼을 누르면 console에 다음과 같이 실행된다.
1 | [OnChanges] |
2) 두번째 객체형 프로퍼티 변경 버튼을 누르면 객체의 프로퍼티 값을 변경하여 자식 컴포넌트에 전송한다. 이때는 객체는 mutable 하므로 객체의 프로퍼티 값을 변경하여도 참조값은 변경되지 않는다. 따라서 입력 프로퍼티가 변경되지 않는 것으로 간주하여 ngOnChanges 가 호출되지 않는다. 다만 angular 변화 감지 로직은 실행되어 ngDoCheck는 호출된다.
1 | [DoCheck] |
디렉티브 생명주기 훅 메소드
디렉티브도 컴포넌트와 동일한 생명주기와 훅 메소드를 가진다. 다만 디렉티브는 뷰가 없기 때문에 뷰와 관련된 생명주기는 존재하지 않는다.
뷰와 관련된 생명주기 : AfterViewInit, AfterViewChecked, AfterContentInit, AfterContentChecked
이를 제외한 ngOnChanges, ngDoCheck, OnInit, OnDestory만 존재한다.