2. 튜토리얼: SPA 라우팅
이 문서는 단일 페이지 애플리케이션(Single Page Application, SPA)에서 Angular 라우터를 활용하는 방법에 대해 설명한다.
SPA에서 모든 애플리케이션 기능은 한 HTMl 화면 안에서 동작한다. 사용자가 애플리케이션 기능을 실행하더라도 브라우저는 화면을 통째로 갱신하지 않고 사용자에게 필요한 부분만 다시 렌더링한다. SPA는 이런 방식으로 UX를 대폭 개선했다.
사용자가 애플리케이션의 특정 화면으로 이동하는 규칙은 라우팅 규칙(Route)으로 정의한다. 라우팅 규칙에는 로그인하지 않았거나 권한이 없는 사용자를 막는 설정도 추가할 수 있다.
1. 목표
- 애플리케이션 기능을 모듈 단위로 구성한다.
- 컴포넌트로 이동하는 방법을 정의한다.
- 화면을 전환하면서 컴포넌트에 인자를 전달한다.
- 필요하다면 라우팅 규칙을 중첩해서 구성할 수 있다.
- 사용자가 라우팅할 수 있는지 검사한다.
- 저장하지 않은 변경사항을 폐기할지 결정한다.
- 라우팅 데이터를 미리 받아오거나 모듈을 지연로딩해서 성능을 개선한다.
- 컴포넌트가 로드될 조건을 추가한다.
2. 사전지식
이 문서를 제대로 이해하려면 이런 내용을 미리 알고 있는 것이 좋다:
- JavaScript
- HTML
- CSS
- Angular CLI
3. 예제 애플리케이션 만들기
npm
명령을 실행하여 Angular CLI를 설치한다.
Note
npm install -g
명령을 실행하여 패키지를 설치하는 경우npx
명령어를 붙이지 않아도 된다.
Angular CLI를 사용해서 angular-router-sample라는 이름으로 애플리케이션을 생성한다. 이 애플리케이션에는 crisis-list와 heroes-list 컴포넌트가 존재한다.
angular-router-sample라는 이름으로 Angular 프로젝트를 생성한다.
Would you like to add Angular routing?
질문에는 N
을 선택한다. Which styleshee format would you like to use?
질문에는 CSS
를 선택한다. 이제 시간이 조금 지나고 나면 angular-router-sample
프로젝트가 생성된다.
터미널에서 angular-router-sample
디렉터리로 이동한다.
crisis-list 컴포넌트를 생성한다.
에디터로 crisis-list.component.html
파일을 열고 이런 내용으로 변경한다.
heroes-list 컴포넌트를 생성한다.
에디터로 heroes-list.component.html
파일을 열고 이런 내용으로 변경한다.
에디터로 app.component.html
파일을 열고 이런 내용으로 변경한다.
<h1>Angular Router Sample</h1>
<app-crisis-list></app-crisis-list>
<app-heroes-list></app-heroes-list>
ng serve
명령을 실행해서 애플리케이션이 제대로 동작하는지 확인한다.
브라우저를 열고 http://localhost:4200
주소로 이동해 보자. 웹 화면이 뜨면 컴포넌트 2개가 함께 표시되는 것을 확인할 수 있다.
4. @angular/router
패키지에서 RouterModule
로드하기
애플리케이션 화면은 URL 주소로 결정된다. 예제로 만드는 애플리케이션에 이런 기능을 추가하려면 app.module.ts
파일이 RouterModule
을 활용하는 방식으로 수정해야 한다. 이 모듈은 @angular/router
패키지로 제공된다.
에디터로 app.module.ts
파일을 연다.
import
구문을 다음과 같이 추가한다.
5. 라우팅 규칙 정의하기
이번 섹션에서는 라우팅 규칙을 2개 정의해 보자:
/crisis-list
라우팅 규칙은crisis-list
컴포넌트를 표시한다./heroes-list
라우팅 규칙은heroes-list
컴포넌트를 표시한다.
라우팅 규칙은 JavaScript 객체로 정의한다. 개별 라우팅 규칙에는 프로퍼티가 2개 있는데, path
에는 라우팅 규칙과 연결될 URL 주소를 문자열로 지정하고, component
에는 해당 주소로 접근했을 때 표시될 컴포넌트를 지정한다.
에디터로 app.module.ts
파일을 연다.
@NgModule()
섹션을 찾는다.
imports
배열을 이런 내용으로 수정한다.
imports: [
BrowserModule,
RouterModule.forRoot([
{path: 'crisis-list', component: CrisisListComponent},
{path: 'heroes-list', component: HeroesListComponent},
]),
],
imports
배열에 RouterModule
을 추가하면서 RouterModule
의 forRoot()
메서드를 사용해서 라우팅 규칙을 2개 정의했다. forRoot()
메서드는 JavaScript 객체 배열을 인자로 받아서 개별 객체마다 라우팅 규칙을 정의한다. forRoot()
메서드를 실행하면 애플리케이션에 RouterModule
인스턴스가 전역 범위에 하나 생성된다.
6. router-outlet
사용하기
이제 애플리케이션에는 라우팅 규칙이 2개 존재한다. 하지만 crisis-list
컴포넌트와 heroes-list
컴포넌트는 app.component.html
템플릿에 하드 코딩되어 있다. 라우팅 규칙을 제대로 활용하려면 URL 주소에 따라 컴포넌트를 동적으로 로딩하는 방식으로 변경해야 한다.
이 기능을 구현하려면 템플릿 파일에 router-outlet
디렉티브를 추가하면 된다.
에디터로 app.component.html
파일을 연다.
아래 두 줄을 삭제한다.
router-outlet
디렉티브를 추가한다.
브라우저에서 변경된 내용을 확인해 보자. 이제 애플리케이션에는 제목만 표시된다. crisis-list
컴포넌트를 확인하려면 브라우저 주소표시줄 뒤에 crisis-list
를 추가하면 된다:
crisis-list
컴포넌트가 표시되는지 확인해 보자. Angular는 라우팅 규칙에 따라 컴포넌트를 동적으로 로드한다. heroes-list
컴포넌트도 같은 방법으로 확인할 수 있다:
7. UI 엘리먼트로 네비게이션 조작하기
애플리케이션에는 라우팅 규칙이 2개 등록되어 있지만, 아직까지는 브라우저 주소표시줄에 주소를 직접 입력해야 라우팅 규칙이 동작하는 것을 확인할 수 있다. 이번 섹션에서는 사용자가 클릭할 수 있는 링크를 추가해서 이 링크로 heroes-list
와 crisis-list
를 전환해 보자. 링크에는 스타일도 적용할 수 있는데, 스타일을 꼭 적용해야 하는 것은 아니지만 현재 화면에 표시되고 있는 컴포넌트가 어떤 것인지 쉽게 확인하는 데에 도움이 될 것이다.
app.component.html
파일을 열고 제목 아래 이런 내용을 추가한다.
<nav>
<a class="button" routerLink="/crisis-list">Crisis Center</a> |
<a class="button" routerLink="/heroes-list">Heroes</a>
</nav>
이 코드는 Angular routerLink
디렉티브를 활용한다. routerLink
디렉티브는 라우팅 규칙과 템플릿을 연결하는 역할을 한다.
app.component.css
파일을 열고 이런 스타일을 추가한다.
.button {
box-shadow: inset 0 1px 0 0 #ffffff;
background: #ffffff linear-gradient(to bottom, #ffffff 5%, #f6f6f6 100%);
border-radius: 6px;
border: 1px solid #dcdcdc;
display: inline-block;
cursor: pointer;
color: #666666;
font-family: Arial, sans-serif;
font-size: 15px;
font-weight: bold;
padding: 6px 24px;
text-decoration: none;
text-shadow: 0 1px 0 #ffffff;
outline: 0;
}
.activebutton {
box-shadow: inset 0 1px 0 0 #dcecfb;
background: #bddbfa linear-gradient(to bottom, #bddbfa 5%, #80b5ea 100%);
border-radius: 6px;
border: 1px solid #84bbf3;
display: inline-block;
cursor: pointer;
color: #ffffff;
font-family: Arial, sans-serif;
font-size: 15px;
font-weight: bold;
padding: 6px 24px;
text-decoration: none;
text-shadow: 0 1px 0 #528ecc;
outline: 0;
}
이제 브라우저에서 애플리케이션을 확인하면 링크가 2개 존재하는 것을 확인할 수 있다. 링크를 클릭하면 해당 링크와 연결된 화면이 표시된다.
8. 활성화된 라우팅 규칙 활용하기
이전 섹션에 추가한 링크를 활용하면 애플리케이션에서 원하는 주소로 이동할 수 있지만, 현재 적용된 라우팅 규칙이 무엇인지는 확인하기 어렵다. Angular routerLinkActive
디렉티브를 활용하면 현재 애플리케이션에 적용된 라우팅 규칙을 확인할 수 있다.
에디터로 app.component.html
파일을 연다.
앵커 태그에 routerLinkActive
디렉티브를 이렇게 추가한다.
<nav>
<a class="button" routerLink="/crisis-list" routerLinkActive="activebutton"
>Crisis Center</a
>
|
<a class="button" routerLink="/heroes-list" routerLinkActive="activebutton"
>Heroes</a
>
</nav>
브라우저에서 애플리케이션을 다시 확인해 보자. 이제 버튼을 클릭하면 현재 사용자가 보고 있는 컴포넌트에 따라 버튼의 스타일이 자동으로 지정된다. routerLinkActive
디렉티브를 활용하면 현재 적용된 라우팅 규칙이 무엇인지 사용자에게 알릴 수 있는 CSS 클래스를 적용할 수 있다. 이번 예제에서는 activebutton
이라는 CSS 클래스를 적용했지만, 어느 이름이든 가능하다.
9. 리다이렉션 추가하기
이번 섹션에서는 /heroes-list
컴포넌트를 표시하도록 리다이렉트하는 라우팅 규칙을 추가해 보자.
에디터로 app.module.ts
파일을 연다.
imports
배열의 RouterModule
섹션을 아래 내용으로 수정한다.
imports: [
BrowserModule,
RouterModule.forRoot([
{path: 'crisis-list', component: CrisisListComponent},
{path: 'heroes-list', component: HeroesListComponent},
{path: '', redirectTo: '/heroes-list', pathMatch: 'full'},
]),
],
새로 추가한 라우팅 규칙은 path
에 빈 문자열이 사용되었다. 그리고 component
프로퍼티 대신 다른 프로퍼티를 사용한다:
redirectTo
: 빈 주소로 접근하면heroes-list
주소로 리다이렉트하도록 지정한다.pathMatch
: Angular가 URL을 어떻게 매칭할지 결정한다. 이 튜토리얼에서는full
이 사용되었는데, 빈 주소를 매칭하려면 이 정책을 사용하는 것이 좋다.
이제 브라우저로 애플리케이션에 접근할 때 빈 주소를 사용하면 heroes-list
컴포넌트로 이동한다.
10. 404 화면 추가하기
개발자가 정의하지 않은 라우팅 규칙으로 사용자가 접근하는 경우가 있을 수 있다. 이런 경우에는 404 화면을 대신 표시하는 방법이 가장 좋다. 이번 섹션에서는 404 화면을 만들고 라우팅 규칙을 수정해서 정의되지 않은 주소로 접근했을 때 이 화면을 표시해 보자.
터미널에서 PageNotFound
컴포넌트를 생성한다.
에디터로 page-not-found.component.html
파일을 열고 이런 내용으로 수정한다.
<h2>Page Not Found</h2>
<p>We couldn't find that page! Not even with x-ray vision.</p>
app.module.ts
파일을 열고 이 파일의 imports
배열 RouterModule
섹션을 이런 내용으로 수정한다.
imports: [
BrowserModule,
RouterModule.forRoot([
{path: 'crisis-list', component: CrisisListComponent},
{path: 'heroes-list', component: HeroesListComponent},
{path: '', redirectTo: '/heroes-list', pathMatch: 'full'},
{path: '**', component: PageNotFoundComponent}
]),
],
**
라는 주소로 라우팅 규칙을 추가한다. 이 라우팅 규칙은 와일드카드 라우팅 규칙(wildcard route)라고 하며, 라우팅 규칙에 등록되지 않은 주소는 모두 이 라우팅 규칙과 매칭된다.
Note
- 와일드카드 라우팅 규칙은 라우팅 규칙을 등록하는 배열 마지막에 등록해야 한다.
- 라우팅 규칙은 순서가 중요한데, Angular는 라우팅 규칙 중에서 첫 번째로 매칭되는 라우팅 규칙을 적용한다.
이제 http://localhost:4200/powers
와 같이 등록되지 않은 주소로 접근해 보자. 해당 주소와 매칭된 라우팅 규칙이 app.module.ts
파일에 존재하지 않지만 애플리케이션에는 와일드카드 라우팅 규칙이 등록되어 있기 때문에 자동으로 PageNotFound
컴포넌트가 화면에 표시된다.