코딩팍

 

 

앵귤러 변경감지 (Change Detection)

앵귤러는 컴포넌트 안에 있는 데이타가 바뀌는 것을 감지하고 자동으로 뷰를 다시 렌더링한다. 기본값으로 설정해 놓으면 다음과 같은 브라우저의 기본적인 기능을 모두 변경감지한다: (완전한 목록은 아님)

 

  • 브라우저 이벤트 (click, mouseover, keyup, 등등)
  • setTimeout() / setInterval()
  • Ajax HTTP 요청

 

당연히 데이타가 변경되는 것을 감지하려면 모든 이벤트를 트래킹해야하는게 아닌가?

그럼 OnPush 전략은 왜 만들어 진걸까?

 

성능 향상 때문이다.

 

💡 OnPush 전략을 사용하면 모든 브라우저 API의 변경감지를 하지 않음으로서 성능향상을 할 수 있다.

 

그렇다고 해서 아무때나 OnPush 전략을 사용할 수 있는 것이 아니다.

OnPush는 모든 이벤트를 감지 하지 않기 때문에 다음과 같이 데이타가 직접적으로 컴포넌트로 주입될 때 사용할 수 있다:

 

  • 직접적으로 input을 받는 컴포넌트
  • Observable input을 가진 컴포넌트
  • 서비스를 통해 데이터를 받는 컴포넌트

 

 

OnPush 변경감지

사용법:

changeDetection: ChangeDetectionStrategy.OnPush, 

 

 

직접적으로 input을 받는 컴포넌트

OnPush를 사용하면 앵귤러는 input의 참조값(reference)을 비교해서 변경 감지를 실행한다.

자바스크립트의 원시 타입 (Primitive data type)은 이미 변경 불가능한 값이라서 따로 관리할 필요가 없다. 원시 타입 변수를 변경할 때 자바스크립트는 자동으로 변경된 값을 새로운 메모리 주소에 만들고 가르킨다.

 

하지만 객체 (Object)는 변경 가능한 값이다. 새로운 값을 다시 만들지 않고 직접 변경이 가능하기 때문이다.

OnPush는 참조값을 비교해서 변경 감지한다. 즉, 객체의 변경 감지를 위해서는:

⇒ 모든 객체를 변경 불가 (immutable)하게 사용해야한다는 뜻이다.

    ⇒ 객체에서 값을 변경할 때 객체의 복사본을 만들어서 해야한다는 뜻이다.

 

 

예시:

user: User = {
        firstName: 'Alice',
        lastName: 'Smith'
};

위와 같은 user의 firstName을 바꾸는 함수가 있다고 가정하자.

 

changeUserName() {
        this.user.firstName = 'Bob';
 }

위에 코드는 this.user 객체를 직접적으로 변경하기 때문에 OnPush 전략 사용시 UI가 업데이트 되지 않는다.

 

해결법:

changeUserName() {
    this.user = {
        firstName: 'Bob',
        lastName: 'Smith'
    }
}

this.user를 새로운 값을 가진 새로운 객체를 만들어서 배정한다. 새로운 객체는 새로운 참조값을 가지고 있기 때문에 OnPush 전략이 변경을 감지한다.

 

 

Observable input을 가진 컴포넌트

Observable input을 사용하려면 async pipe를 사용하는 것이 좋다.

async pipe는 markForCheck()를 이용하기 때문에 앵귤러는 Observable이 값을 방출할때 뷰가 바뀐다는 것을 알 수있다.

 

예시:

ngOnInit() {
        this.userService.user$.subscribe(
          user => this.firstName = user.firstName
        );
}

코드 내에서 subscribe 하는 것 보다

 

<fieldset class="newsletter" *ngIf="userService.user$ | async as user else loading">

템플릿에서 async pipe를 통해 subscribe 하는 것이 더 효과적이다!

 

 

💡 OnPush 컴포넌트가 많을 수록 앵귤러는 더 적게 변경을 체크한다. 그러니 최대한 OnPush에 최적화 된 컴포넌트를 만드는 것이 좋다.

 

 

이 글을 공유합시다

facebook twitter googleplus kakaoTalk kakaostory naver band