Tutorial: Tour of Heroes - Create a Feature Component

kukudas·2022년 2월 15일
0

Angular

목록 보기
5/15

Create a featrue component

지금은 HeroesComponent가 hero list랑 선택한 hero의 detail까지 모두 보여주고 있음.

이렇게 기능들을 하나의 컴포넌트에 몰아두는 것은 앱이 커지면 커질수록 관리하기가 힘들어지기 때문에
커다란 컴포넌트를 각각의 task나 workflow에 맞춰서 작은 sub-component로 분리하는게 좋음

여기서는 HeroesComponent는 hero의 list만 보여주게 할거고 새로 만들 HeroDetailComponent
선택한 heor의 detail만 보여줄 것임.

Make the HeroDetailComponent

C:\Users\Home\Desktop\angular\angular-tour-of-heroes\src\app
에서

ng generate component hero-detail

명령어를 사용해서 hero-detail이라는 컴포넌트 만들었음.

위 명령어는 src/app/hero-detail이라는 디렉토리를 생성하고 이 디렉토리 안에는 아래 4개의 파일이 생성됨.

  • 컴포넌트 스타일을 위한 CSS 파일
  • 컴포넌트 템플릿을 위한 HTML 파일
  • HeroDetailComponent 컴포넌트 클래스가 있는 타입스크립트 파일
  • HeroDetailComponent 클래스의 테스트파일(hero-detail.component.spec.ts 파일)

명령어는 HeroDetailComponentsrc/app/app.module.ts파일의 @NgModule 데코레이터에 추가해줌.

@NgModule({
  declarations: [
    AppComponent,
    HeroesComponent,
    // HeroDetailComponent 추가됨을 볼 수 있음.
    HeroDetailComponent
  ],

Write the template

HerosComponent 템플릿에 있는 hero detail 관련 HTML을 잘라서 HeroDetailComponent 템플릿에 붙여줌.

이렇게 잘라온 HTML은 selectedHero를 참조하고 있는데, 새로 만든 HeroDetailComponent 템플릿은 selected hero말고
어떤 hero라도 보여주도록 할거여서 템플릿의 selectedHerohero로 대체하기.

<!--
	src/app/hero-detail/hero-detail.componenth.html
-->
<div *ngIf="selectedHero">

  <h2>{{hero.name | uppercase}} Details</h2>
  <div>id: {{hero.id}}</div>
  <div>
    <label for="hero-name">Hero name: </label>
    <input id="hero-name" [(ngModel)]="hero.name" placeholder="name">
  </div>

</div>

Add the @Input() hero property

HeroDetailComponent 템플릿은 Hero 타입인 컴포넌트의 hero property를 bind 하니
아래처럼 Hero 인터페이스 import 해야함.

// src/app/hero-detail/hero-detail.component.ts
import { Hero } from '../hero';

외부 컴포넌트인 HeroesComponent가 아래처럼 hero에 bind할 거라서
hero property는 Input property여야 하기 때문에 @Input() 데코레이터를 사용해야함.

<app-hero-detail [hero]="selectedHero"></app-hero-detail>

@Input을 사용하기 위해서 Input@angular/core에서 import 해줌.

// src/app/hero-detail/hero-detail.component.ts
import { Component, OnInit, Input } from '@angular/core';

이제 hero property를 @Input() 데코레이터를 붙여서 추가해줌.

// src/app/hero-detail/hero-detail.component.ts
export class HeroDetailComponent implements OnInit {
  @Input() hero?: Hero;

  constructor() { }

  ngOnInit(): void {
  }

}

Show the HeroDetailComponent

이전에 만들었던 HeroesComponent는 hero detail도 보여주는 기능이 있었는데 이제 이 기능을
HeroDetailComponent로 옮겨야함.

HeroesComponentHeroDetailComponent는 parent/child 관계를 가지게 될것임.
부모인 HeroesComponent는 유저가 hero 리스트에서 선택한 hero
를 보내서 자식인 HeroDetailComponent에 보내줄것임.

HeroesCompoent 클래스를 수정할 필요는 없지만 템플릿은 수정해야함.

Update the HeroesComponent template

HeroDetailComponent의 selector는 app-hero-detail'이니 ' element를 HeroesComponent
템플릿 맨 아래쪽에다가 추가해줌. 추가로 HeroesComponent.selectedHero property를 element의 hero
property에 아래처럼 추가해줌.

<!--
	heroes.component.html
-->
<app-hero-detail [hero]="selectedHero"></app-hero-detail>

[hero]="selectedHero"는 앵귤러의 property binding임. 이 바인딩은 아래의 HerosComponent클래스의selectedHero` property를

// src/app/heroes/HeroesComponent.ts
export class HeroesComponent implements OnInit {
  selectedHero?: Hero;
}

target element인 app-hero-detailhero property 즉, HeroDetailComponenthero property에
매핑시켜줌.
아래 코드는 HeroDetailComponenthero property임..

// src/app/heroe-detail/HeroeDetailComponent.ts
ts
export class HeroDetailComponent implements OnInit {
  @Input() hero?: Hero;
  }
}

이제 유저가 리스트에 있는 hero를 클릭하게되면 selectedHeor가 변하고 property binding이
<app-hero-detail [hero]="selectedHero"></app-hero-detail>hero를 업데이트해서
HeroDetailComponent가 새로운 hero를 보여주게됨.

아래는 위 기능을 적용한 HeroesComponent 템플릿임.

<!--
	heroes.component.html
-->
<h2>My Heroes</h2>
<ul class="heroes">
  <li *ngFor="let hero of heroes">
    <button [class.selected]="hero === selectedHero" type="button" (click)="onSelect(hero)">
      <span class="badge">{{hero.id}}</span>
      <span class="name">{{hero.name}}</span>
    </button>
  </li>
</ul>

<app-hero-detail [hero]="selectedHero"></app-hero-detail>

다 하면 아래 처럼 잘 나옴을 볼 수 있음.

What Changed:

기능 자제는 이전이랑 똑같이 유저가 hero를 클릭하면 hero detail이 hero list 밑에 나오게됨.
다른 점은 HerosComponet에서 detail을 보여주던 기능이 HeroDetailComponent로 옮겨간것임.

이렇게 컴포넌트를 기능별로 세분화하면
1. HeroesComponet가 해야할 일이 줄어들고
2. parent인 HeroesComponet를 건들지 않아도 HeroDetailComponent를 수정할 수 있음.
3. hero detail view를 건들이지 않아도 HeroesComponet 바꿀 수 있음.
4. HeroesDetailComponet를 다른 컴포넌트에서도 사용할 수 있음.

Summary

  • 별도의 재사용가능한 `HeroDetailComponent를 만들었음
  • property binding을 사용해서 parent인 HeroesComponet가 child인 HeroDetailComponet에 대한 제어권한을 가지게 됨.
  • @Input 데코레이터를 사용해서 hero property가 외부 컴포넌트인 HeroesComponent에서 바인딩할 수 있게 했음.

출처

0개의 댓글