홈으로 돌아가기

Angular 템플릿의 순수 함수 21.2

버전 21.2부터 Angular는 컴포넌트 메서드 없이 템플릿에서 필터링, 검색 및 signal 업데이트를 위한 순수 JS 함수를 지원합니다. 네비게이션, 정렬, input 예제를 통한 함수 전달 분석. 제한 사항: 함수 내부 multiline 표현식 및 파이프 금지.

Angular 템플릿의 함수: 클래스 없이 필터링 및 정렬
Advertisement 728x90

Angular 21.2 템플릿에서 순수 함수 사용하기: 기능과 제약사항

Angular 21.2 버전부터는 컴포넌트 클래스에 메서드를 선언하지 않고도 HTML 템플릿에서 순수 JavaScript 함수를 직접 사용할 수 있습니다. 이는 시그널 기반의 배열 필터링이나 계산과 같은 데이터 처리를 단순화하지만, 순수 함수 규칙을 엄격히 준수해야 합니다.

영웅 목록을 가진 컴포넌트를 예로 들어보겠습니다. 데이터는 WritableSignal<Hero[]> 타입의 heroes 시그널에 저장됩니다:

import { Component, signal, WritableSignal } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HeroesList } from '../heroes-list/heroes-list';

export interface Hero {
  id: number;
  name: string;
  lastName: string;
  nickname: string;
  email: string;
}

@Component({
  selector: 'app-heroes',
  imports: [HeroesList, CommonModule],
  templateUrl: './heroes.component.html',
  styleUrl: './heroes.component.scss',
  standalone: true
})
export class HeroesComponent {
  heroes: WritableSignal<Hero[]> = signal<Hero[]>([
    // hero data
  ]);

  selectedHeroId: WritableSignal<number> = signal<number>(1);
}

@for를 통한 기본 목록 출력:

Google AdInline article slot
<ul>
  @for (hero of heroes(); track $index) {
    <li>{{ `${hero.name} ${hero.lastName} - ${hero.email}` }}</li>
  }
</ul>

컴포넌트 메서드 없이 목록 탐색하기

이제 selectedHeroId 시그널 업데이트는 클릭 핸들러에서 인라인으로 수행됩니다. prevHero()nextHero() 메서드 대신, 람다 함수를 사용한 update()가 활용됩니다:

<div class="hero-navigation">
  <button (click)="selectedHeroId.update(count => count === 1 ? heroes().length : count - 1)">이전</button>
  <div class="hero-name">
    {{ heroes()[selectedHeroId() - 1].name + ' ' + heroes()[selectedHeroId() - 1].lastName }}
  </div>
  <button (click)="selectedHeroId.update(count => count === heroes().length ? 1 : count + 1)">다음</button>
</div>
<div class="hero-info">
  {{ heroes()[selectedHeroId() - 1] | json }}
</div>

이로 인해 보일러플레이트 코드가 줄어들지만, 순환 탐색 로직(첫 번째 요소로 돌아가기)은 여전히 템플릿에 남아 있습니다.

템플릿에서 필터링 및 검색하기

이름과 성의 첫 글자가 일치하는 영웅 필터링:

Google AdInline article slot
<div>
  {{ heroes().filter(hero => hero.name.charAt(0).toLowerCase() === hero.lastName.charAt(0).toLowerCase())
    .map(hero => `${hero.name} ${hero.lastName}`).join(', ') }}
</div>

결과: Peter Parker, Stephen Strange, Bruce Banner.

이메일 도메인으로 검색:

<div>
  {{ heroes().find(hero => hero.email.endsWith('stark.com'))?.name }}
</div>

출력: Tony.

Google AdInline article slot

자식 컴포넌트에 함수를 입력으로 전달하기

자식 컴포넌트 HeroesListinput을 통해 정렬 함수를 받습니다:

@Component({
  selector: 'app-heroes-list',
  template: `
    <ul>
      @for (hero of sortedHeroes(); track $index;) {
        <li>{{ hero.name + ' ' + hero.lastName }}</li>
      }
    </ul>
  `,
  standalone: true
})
export class HeroesList {
  heroes: InputSignal<Hero[]> = input.required<Hero[]>();
  sortFn: InputSignal<(a: Hero, b: Hero) => number> = input.required<(a: Hero, b: Hero) => number>();

  sortedHeroes: Signal<Hero[]> = computed(() => [...this.heroes()].sort(this.sortFn()));
}

부모 템플릿에서의 사용법:

<app-heroes-list [heroes]="heroes()" [sortFn]="(a, b) => a.name.localeCompare(b.name)"></app-heroes-list>

이름으로 정렬된 결과: Bruce Banner, Natasha Romanoff, Peter Parker, Stephen Strange, Tony Stark.

함수 내 객체와 리터럴

객체를 반환하기 위해, 함수를 괄호로 감싸 함수 본문과 구분합니다:

<ul>
  @for (hero of heroes().map(item => ({ name: 'Super ' + item.nickname, email: item.email })); track $index) {
    <li>{{ `${hero.name} - ${hero.email}` }}</li>
  }
</ul>

결과: Super Spider man - [email protected] 등.

순수 함수의 제약사항

  • 여러 줄 함수는 지원되지 않습니다:

```html

{{ heroes().map(item => { return { name: 'Super ' + item.nickname, email: item.email } }) }}

```

컴파일러가 오류를 발생시킵니다.

  • 함수를 반환하는 함수는 텍스트로 컴파일됩니다:

```html

{{ () => heroes().find(hero => hero.email.endsWith('stark.com'))?.name }}

```

  • 함수 내부의 파이프는 순수 JS가 아니므로 금지됩니다:

```html

{{ heroes().find(hero => hero.email.endsWith('StaRk.com' | lowercase))?.name }}

```

결과에 파이프를 적용하는 것은 허용됩니다:

```html

{{ heroes().find(hero => hero.email.endsWith('stark.com'))?.name | uppercase }}

```

결과: TONY.

핵심 요약

  • Angular 21.2 템플릿의 순수 함수는 시그널을 이용한 간단한 연산(필터링, 검색, 값 업데이트)에 적합합니다.
  • 객체 리터럴에는 괄호 사용이 필수이며, 여러 줄 표현식은 금지됩니다.
  • 입력 시그널을 통해 함수를 전달하면 자식 컴포넌트에서 반응성을 유지합니다.
  • 함수 내부에서 파이프 사용을 피하고, 결과에만 적용하세요.
  • 성능: 순수 함수는 변경 감지마다 재계산됩니다; 복잡한 로직에는 computed나 파이프를 선호하세요.

— Editorial Team

Advertisement 728x90

다음 읽기