Angular Change Detection과 OnChanges, DoCheck

Jeongkuk Seo
sjk5766
Published in
6 min readDec 24, 2018

이 글에서는 Angular의 Change Detection (변경 감지)의 기반이 되는 zone.js에 대해 간단히 알아보고 변경감지 라이프 사이클 메소드 OnChanges와 DoCheck의 특징과 차이점을 살펴보도록 하겠습니다. (본 글에서 변경감지 라는 단어와 Change Detection은 동일한 의미입니다.)

zone.js

Angular에서 비 동기 통신, 사용자 이벤트(클릭 이벤트 등)에 의해 데이터가 변경 될 경우 이를 화면에 반영해야 합니다. 이는 Angular가 데이터가 변경되는 것을 감지할 수 있어야 한다는 의미입니다.

Angular에서는 변경 감지를 위해 zone.js를 사용합니다. zone.js는 사용자 이벤트, SetTimeout, Ajax 통신과 같은 Native API를 몽키패치 하여 해당 API가 실행된 후에 Angular에게 통지하며, 통지를 받은 Angular는 변경감지를 수행합니다.

OnChanges 라이프 사이클 메소드

개발자 입장에서 변경 감지에 따른 기능을 만든다. 이 때 가장 만만한 녀석은 OnChanges 메소드입니다. 이 메소드가 호출되는 시점은 자식 컴포넌트가 부모로 부터 전달받은 데이터가 초기화 되는 시점과 그 후에 변경될 때마다 호출됩니다. 예제를 보겠습니다.

위 코드를 간단 요약하면 부모와 자식 컴포넌트가 데이터를 공유하고 있으며 버튼을 클릭하게 되면 데이터가 변경되는 코드입니다. 실행을 시키고 버튼을 여러번 클릭해 보면 정상적으로 변경감지가 수행된 것을 확인할 수 있습니다.

OnChanges 메소드는 값의 변화를 살펴봅니다. 즉, Input 데코레이터로 전달 받은 데이터가 변경되지 않으면 호출되지 않습니다. 위 예제에서 변경되는 데이터로 문자열을 사용했지만, 만약 객체라면 어떻게 될까요? 자바스크립트에서 객체는 {key : value} 에서 value가 변경되어도 변수가 가리키는 레퍼런스는 변경되지 않습니다.

결론부터 말하면 레퍼런스가 변경되지 않으면 OnChanges는 호출되지 않습니다. 다르게 말하면 객체의 value 변경은 OnChanges로 탐지할 수 없습니다. 위 소스에서 부모의 컴포넌트 클래스만 아래처럼 변경 하겠습니다.

export class AppComponent {
data = {name : ‘seo’}
change() {
this.data.name = this.data.name + ‘1’;
}
}

변경 된 것은 data 변수가 string에서 object로 변경되었습니다. 버튼이 클릭되면 name에 해당되는 value에 문자열 1을 더하고 있습니다. 그리고 다시 말하지만 이는 value의 변경이지 레퍼런스의 변경은 아닙니다. 결과는 아래와 같습니다.

버튼을 아무리 눌러도 크롬에선 console.log를 확인할 수 없습니다. 우측에 나온 데이터는 최초 값이 초기화 될 때 찍힌 것이며, 이 후 버튼 클릭에도 변경되지 않습니다. Angular에서 객체의 value의 변경을 탐지하기 위해선 DoCheck 메소드를 사용할 수 있습니다.

DoCheck

DoCheck가 OnChanges 메소드와 다른점은 Change Detection을 변경감지 프로세스가 진행될 때 마다 호출됩니다. 즉 값의 변화를 확인하는게 아니라, 변경 감지가 수행될 떄 호출됩니다. 예제를 위해 자식 컴포넌트 클래스에 아래와 같이 ngDoCheck를 추가 하겠습니다.

export class ChildComponent implements OnChanges, DoCheck {
@Input() data: object;

ngOnChanges(changes: SimpleChanges) {
console.log(‘child OnChanges()’)
console.log(changes)
}
ngDoCheck() {
console.log(‘child DoCheck!!’)
}
}

DoCheck는 변경 감지가 수행될 떄마다 호출되므로 버튼을 클릭하면 아래와 같이 console 로그를 확인할 수 있습니다.

DoCheck를 구현하여 변경을 감지할 때, 로직은 매우 단순해야 합니다. 어플리케이션이 커질수록 변경감지가 빈번할 것이고, 이 때마다 호출되는 DoCheck 메소드에 복잡한 로직을 구현하면 이는 성능에 심각한 부하를 발생시킬 수 있습니다.

간단 요약

  1. zone.js는 비 동기 Native API들을 몽키패치 하여, 작업을 수행 후 angular에게 통보한다. 이 통보 메시지를 받은 후 변경 감지가 수행된다.
  2. OnChanges 메소드를 통해 Input 데코레이터로 전달 된 데이터의 변경을 감지할 수 있다. 객체와 같은 value의 변경은 OnChanges 메소드로 탐지할 수 없다.
  3. DoCheck 메소드는 변경 감지 프로세스가 수행 될 때마다 호출되며 복잡한 로직의 구현은 어플리케이션 성능에 영향이 있으니 피해야한다.

More

Angular의 변경 감지는 성능에 영향을 줄 정도로 중요한 부분입니다. 변경 감지의 성능을 향상하기 위해 바로 다음글을 링크합니다.

--

--