[Angular] 데코레이터(Decorator) 소개 및 사용방법(2)

Angular Decorator는 Angular 애플리케이션 구축의 기본 측면입니다. 이는 Angular에 처리 및 사용 방법을 알려주는 메타데이터를 제공하여 클래스, 속성, 메서드 및 매개 변수의 동작을 향상시키는 데 사용됩니다.

이 글에서는 Angular의 다양한 데코레이터 유형을 살펴보고 이를 효과적으로 사용하는 시기와 방법을 알아봅니다.

@NgModule

@NgModule은 Angular 모듈을 생성하고 구성하는 데 사용되는 데코레이터입니다. Angular 모듈은 components, services, directives, pipes 등과 같은 애플리케이션의 다양한 부분을 위한 컨테이너입니다. 이는 애플리케이션의 여러 부분 간의 종속성을 구성하고 관리하는 데 사용됩니다.

@NgModule 데코레이터를 사용하는 방법의 예는 다음과 같습니다.

1
2
3
4
5
6
7
8
9
10
11
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';

@NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}

위의 예에서는 BrowserModule과 AppComponent를 가져오고 declarations 배열에서 AppComponent를 선언합니다. 또한 bootstrap 컴포넌트를 AppComponent로 지정합니다.

@NgModule 데코레이터에는 구성할 수 있는 여러 속성이 있습니다.

  • declarations: 이 모듈에 속하는 components, directives 및 pipes의 배열입니다.
  • imports: 이 모듈이 의존하는 모듈의 배열입니다.
  • exports: 다른 모듈에서 사용할 수 있는 components, directives 및 pipes의 배열입니다.
  • providers: 이 모듈에서 제공하는 서비스 배열입니다.
  • bootstrap: 이 모듈에 의해 부트스트랩되어야 하는 주요 컴포넌트입니다.

@NgModule 데코레이터를 사용하면 Angular 애플리케이션에서 모듈을 쉽게 만들고 관리할 수 있습니다.

@Optional

@Optional 데코레이터는 종속성을 컴포넌트나 서비스에 주입할 때 종속성을 선택적으로 허용하는 데 사용됩니다. 종속성을 찾을 수 없는 경우 injector 는 오류를 발생시키지 않고 대신 종속성에 대해 null 값을 제공합니다.

예는 다음과 같습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { Component, Optional } from '@angular/core';
import { MyService } from './my.service';

@Component({
selector: 'my-component',
template: '<p>{{ message }}</p>',
})
export class MyComponent {
constructor(@Optional() private myService: MyService) {}

get message(): string {
if (this.myService) {
return this.myService.getMessage();
} else {
return 'MyService not available.';
}
}
}

이 예에서 MyService 종속성은 @Optional 데코레이터를 사용하여 선택 사항으로 표시됩니다. 서비스를 찾을 수 없으면 message() 메서드는 오류를 발생시키는 대신 기본 문자열을 반환합니다.

선택 사항으로 표시된 종속성이 실제로 컴포넌트나 서비스의 올바른 작동을 위해 필요한 경우 @Optional 데코레이터를 사용해서는 안 된다는 점에 유의하는 것이 중요합니다. 대신 종속성을 필수로 표시하고 적절한 오류 처리를 구현해야 합니다.

@Self

@Self 데코레이터는 종속성 해결 범위를 현재 컴포넌트 또는 디렉티브 인스턴스로 제한하는 데 사용됩니다. 즉, Angular는 컴포넌트나 디렉티브의 자체 인젝터에서만 종속성을 찾고 상위 인젝터에서는 찾지 않습니다.

@Self를 사용하는 방법의 예는 다음과 같습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { Component, OnInit, Self } from '@angular/core';
import { MyService } from './my-service';

@Component({
selector: 'my-component',
template: '<p>{{ message }}</p>',
providers: [MyService],
})
export class MyComponent implements OnInit {
message: string;

constructor(@Self() private myService: MyService) {}

ngOnInit() {
this.message = this.myService.getMessage();
}
}

이 예에서는 @Self 데코레이터를 사용하여 MyService 종속성을 MyComponent 컴포넌트에 주입합니다. MyService 종속성은 컴포넌트 수준에서 정의됩니다. 즉, 현재 컴포넌트에만 사용할 수 있고 상위 컴포넌트에는 사용할 수 없습니다.

MyService 종속성이 AppModule 또는 상위 컴포넌트와 같이 더 높은 수준에서 정의된 경우 Angular는 이를 찾을 때까지 현재 컴포넌트의 인젝터, 그 다음 상위 인젝터 등에서 이를 찾습니다. 그러나 @Self데코레이터를 사용하면 종속성 해결 범위를 현재 컴포넌트로만 제한합니다.

요약하자면, @Self 데코레이터는 상위 컴포넌트나 디렉티브가 아닌 현재 컴포넌트나 디렉티브의 컨텍스트 내에서만 종속성을 확인하는 데 사용됩니다.

@SkipSelf

@SkipSelf 데코레이터는 Angular에서 컴포넌트 계층 내 서비스의 가시성과 주입을 제어하는 데 사용됩니다. 컴포넌트나 디렉티브가 서비스를 요청하면 Angular는 현재 인젝터에서 이를 찾기 시작하고 요청된 서비스를 찾거나 트리 상단에 도달할 때까지 인젝터 트리를 탐색합니다.

기본적으로 컴포넌트나 디렉티브가 서비스를 요청하면 Angular는 현재 인젝터에서 해당 서비스를 찾습니다. 즉, 컴포넌트와 모든 하위 컴포넌트에서 서비스를 사용할 수 있다는 뜻입니다. 그러나 어떤 경우에는 현재 인젝터를 건너뛰고 상위 인젝터에서 서비스를 찾을 수 있습니다. 이는 서비스가 동일한 상위를 가진 여러 컴포넌트 간에 공유된다는 의미입니다.

@SkipSelf 데코레이터는 Angular에게 현재 인젝터를 건너뛰고 상위 인젝터에서 요청된 서비스를 찾도록 지시하는 데 사용됩니다. 이는 상위가 동일하지만 서로 직접적으로 관련되지 않은 여러 컴포넌트 간에 서비스를 공유하려는 경우에 유용합니다.

@SkipSelf 데코레이터를 사용하는 방법의 예는 다음과 같습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { Component, Inject, SkipSelf } from '@angular/core';
import { MyService } from './my.service';

@Component({
selector: 'my-child-component',
template: ` <p>My Child Component</p> `,
providers: [{ provide: MyService, useValue: { message: 'Hello from child component!' } }],
})
export class MyChildComponent {
constructor(@SkipSelf() private myService: MyService) {}

ngOnInit() {
console.log(this.myService.message); // Output: "Hello from parent component!"
}
}

이 예에서 MyChildComponent@SkipSelf 데코레이터를 사용하여 상위 인젝터에서 MyService를 요청합니다. 상위 컴포넌트는 providers 배열을 사용하여 MyService를 제공합니다. 이는 모든 하위 컴포넌트에서 서비스를 사용할 수 있음을 의미합니다. MyChildComponent가 초기화되면 상위 컴포넌트의 메시지를 기록합니다.

전반적으로 @SkipSelf 데코레이터는 동일한 부모를 가진 여러 컴포넌트 간에 서비스를 공유하고 동일한 컴포넌트 계층 내에서 동일한 서비스를 여러 번 주입하지 않으려는 경우에 유용합니다.

@ViewChild

@ViewChild 데코레이터는 컴포넌트의 템플릿 보기에서 element 또는 컴포넌트의 참조를 가져오는 데 사용됩니다. 하위 컴포넌트 또는 상위 컴포넌트에 있는 element의 속성 및 메서드에 액세스하는 데 사용할 수 있습니다.

@ViewChild와 함께 사용할 수 있는 selectors에는 두 가지 유형이 있습니다.

  1. Component Selector가 사용되면 @ViewChild는 컴포넌트 인스턴스에 대한 참조를 반환합니다.

다음은 Component Selector와 함께 @ViewChild를 사용하는 예입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { Component, ViewChild } from '@angular/core';
import { ChildComponent } from './child.component';

@Component({
selector: 'parent-component',
template: '<child-component></child-component>',
})
export class ParentComponent {
@ViewChild(ChildComponent) childComponentRef: ChildComponent;

ngAfterViewInit() {
this.childComponentRef.doSomething();
}
}

이 예제에서는 @ViewChild를 사용하여 ChildComponent 인스턴스에 대한 참조를 가져온 다음 doSomething 메서드를 호출하는 데 사용합니다.

  1. 템플릿 참조 변수(Template Reference Variable): 템플릿 참조 변수가 사용되면 @ViewChild는 해당 변수와 연결된 요소 또는 컴포넌트에 대한 참조를 반환합니다.

다음은 템플릿 참조 변수와 함께 @ViewChild를 사용하는 예입니다.

1
<child-component #child></child-component>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { Component, ViewChild } from '@angular/core';
import { ChildComponent } from './child.component';

@Component({
selector: 'parent-component',
template: '<child-component #child></child-component>',
})
export class ParentComponent {
@ViewChild('child') childComponentRef: ChildComponent;

ngAfterViewInit() {
this.childComponentRef.doSomething();
}
}

이 예에서 @ViewChild는 템플릿 참조 변수 #child를 사용하여 ChildComponent 인스턴스에 대한 참조를 가져오는 데 사용됩니다.

@ViewChild는 하위 컴포넌트가 상위 컴포넌트보다 먼저 렌더링되는 경우에만 작동한다는 점에 유의하는 것이 중요합니다. 상위 컴포넌트가 렌더링되기 전에 하위 컴포넌트에 액세스하려고 하면 결과가 정의되지 않습니다. 이를 방지하려면 ngAfterViewInit() 생명주기 훅 메소드를 사용하여 @ViewChild로 액세스를 시도하기 전에 하위 컴포넌트가 렌더링되었는지 확인할 수 있습니다.

@ViewChildren

@ViewChildren 데코레이터는 컴포넌트 또는 디렉티브의 템플릿에서 selector와 일치하는 요소의 QueryList를 가져오는 데 사용됩니다.

다음은 @ViewChildren을 사용하여 특정 디렉티브가 있는 하위 요소의 QueryList를 가져오는 방법에 대한 예입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import { Component, Directive, ViewChildren } from '@angular/core';

@Directive({
selector: '[myDirective]',
})
export class MyDirective {}

@Component({
selector: 'my-component',
template: `
<div myDirective></div>
<div myDirective></div>
<div></div>
`,
})
export class MyComponent {
@ViewChildren(MyDirective) myDirectives: QueryList<MyDirective>;

ngAfterViewInit() {
// Access the elements with MyDirective
this.myDirectives.forEach((directive) => {
console.log(directive);
});
}
}

이 예에서는 @ViewChildren을 사용하여 MyComponent 템플릿의 MyDirective 디렉티브가 있는 요소의 QueryList를 가져옵니다. ngAfterViewInit 생명주기 훅 메소드는 요소에 액세스하고 이를 콘솔에 기록하는 데 사용됩니다.

@ViewChildren 데코레이터는 템플릿의 요소와 일치하도록 디렉티브 유형 대신 문자열 selector를 사용할 수도 있습니다.

결론

이러한 데코레이터를 적절하게 사용하면 Angular 컴포넌트, 디렉티브 및 서비스의 기능을 향상하고 필요한 상용구 코드의 양을 줄일 수 있습니다. 각 데코레이터는 고유한 목적을 수행하며 사용법을 익히면 강력하고 효율적인 Angular 애플리케이션을 만들 수 있습니다.

Share