0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Angular技術要素解説】ルーティングの仕組みを理解する:Router・Guard・Resolverまで

0
Posted at

はじめに

Angular技術要素解説シリーズ、第5弾です。

今回は、SPA(シングルページアプリケーション)において「URLに応じて画面を切り替える」ための仕組み、ルーティングを解説します。

Angularは@angular/routerとして、ルーティング機能を標準搭載しています。

この記事で扱う技術要素

  • Router(ルーター)の基本
  • ルートパラメータ
  • Route Guard(ルートガード)
  • Resolver(リゾルバー)
  • 遅延読み込み(Lazy Loading)

SPAにおけるルーティングとは

従来のWebサイトは、リンクをクリックするたびにサーバーへ新しいHTMLを要求し、ページ全体を再読み込みしていました。

一方AngularのようなSアプリでは、最初に1つのHTMLだけを読み込み、その後はURLの変化に応じてJavaScript側で表示するコンポーネントだけを切り替えるという仕組みを取ります。

この「URLとコンポーネントの対応関係を管理する」機能がルーティングです。

Routerの基本設定

// app.routes.ts
import { Routes } from '@angular/router';
import { HomeComponent } from './home.component';
import { AboutComponent } from './about.component';
import { UserDetailComponent } from './user-detail.component';

export const routes: Routes = [
  { path: '', component: HomeComponent },            // ルートURL(例: /)
  { path: 'about', component: AboutComponent },       // /about
  { path: 'users/:id', component: UserDetailComponent }, // /users/123 のような動的なパス
  { path: '**', redirectTo: '' },                     // どれにも一致しない場合のフォールバック
];
// main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { provideRouter } from '@angular/router';
import { AppComponent } from './app.component';
import { routes } from './app.routes';

bootstrapApplication(AppComponent, {
  providers: [provideRouter(routes)], // ルート設定をアプリに登録する
});
// app.component.ts
import { Component } from '@angular/core';
import { RouterOutlet, RouterLink } from '@angular/router';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [RouterOutlet, RouterLink],
  template: `
    <nav>
      <a routerLink="/">ホーム</a>
      <a routerLink="/about">概要</a>
    </nav>

    <!-- 現在のURLに対応するコンポーネントが、ここに描画される -->
    <router-outlet></router-outlet>
  `,
})
export class AppComponent {}

<router-outlet>は「現在のURLに対応するコンポーネントの表示場所」を示す特殊なタグです。

routerLinkディレクティブを使うと、通常の<a href="...">のようにページ全体をリロードせず、Angular側でURLとコンポーネントだけを切り替えられます。

ルートパラメータの取得

users/:idのような動的なパスに含まれる値(パラメータ)は、以下のように取得します。

// user-detail.component.ts
import { Component, inject } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

@Component({
  selector: 'app-user-detail',
  standalone: true,
  template: `<p>ユーザーID: {{ userId }}</p>`,
})
export class UserDetailComponent {
  private route = inject(ActivatedRoute);

  // "users/123" というURLでアクセスされた場合、userIdには "123" が入る
  userId = this.route.snapshot.paramMap.get('id');
}

/users/123にアクセスすると、UserDetailComponentが表示され、userIdには"123"という文字列が格納されます。

同じコンポーネント内でURLが/users/123から/users/456に変わるようなケース(パラメータだけが変わる遷移)を検知したい場合は、snapshotではなくroute.paramMapをSignal/Observableとして購読する方法も用意されています。

Route Guard(ルートガード)

ルートガードは、特定のルートへの遷移を許可するかどうかを判定する仕組みです。

「ログインしていないユーザーを、マイページへアクセスさせない」といった認可制御によく使われます。

// auth.guard.ts
import { inject } from '@angular/core';
import { CanActivateFn, Router } from '@angular/router';
import { AuthService } from './auth.service';

export const authGuard: CanActivateFn = () => {
  const authService = inject(AuthService);
  const router = inject(Router);

  if (authService.isLoggedIn()) {
    return true; // 遷移を許可
  }

  router.navigate(['/login']); // ログイン画面へリダイレクト
  return false; // 遷移を拒否
};
// app.routes.ts
import { authGuard } from './auth.guard';

export const routes: Routes = [
  { path: 'mypage', component: MyPageComponent, canActivate: [authGuard] },
];

canActivateにガード関数を指定することで、/mypageへのアクセス時に必ずこのチェックが実行されます。

近年のAngularでは、クラスベースのガードではなく、上記のような関数ベースのガード(CanActivateFn)が推奨されています。

Resolver(リゾルバー)

リゾルバーは、ルート遷移が完了する前に、必要なデータを事前に取得しておく仕組みです。

「画面が表示された直後にローディング状態を経てデータが出る」のではなく、「データが揃ってから画面を表示する」という体験を作りたい場合に使います。

// user.resolver.ts
import { inject } from '@angular/core';
import { ResolveFn } from '@angular/router';
import { UserService } from './user.service';
import { User } from './user.model';

export const userResolver: ResolveFn<User> = (route) => {
  const userService = inject(UserService);
  const id = route.paramMap.get('id')!;
  return userService.fetchUserById(id); // Observable/Promiseを返すと、解決を待ってから画面遷移する
};
// app.routes.ts
export const routes: Routes = [
  {
    path: 'users/:id',
    component: UserDetailComponent,
    resolve: { user: userResolver }, // "user"というキーで解決済みデータを渡す
  },
];
// user-detail.component.ts
import { Component, inject } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

@Component({
  selector: 'app-user-detail',
  standalone: true,
  template: `<p>{{ user.name }}さんの詳細ページ</p>`,
})
export class UserDetailComponent {
  private route = inject(ActivatedRoute);
  user = this.route.snapshot.data['user']; // resolveで取得済みのデータをそのまま受け取れる
}

遅延読み込み(Lazy Loading)

大規模なアプリでは、すべてのコンポーネントのコードを最初に一括で読み込むと、初期表示が遅くなってしまいます。

遅延読み込みを使うと、特定のルートに実際にアクセスされたタイミングで、そのルートに必要なコードだけを読み込むようにできます。

// app.routes.ts
export const routes: Routes = [
  { path: '', component: HomeComponent },
  {
    path: 'admin',
    // "admin"にアクセスされて初めて、admin.routesのファイルが読み込まれる
    loadChildren: () => import('./admin/admin.routes').then(m => m.adminRoutes),
  },
  {
    path: 'settings',
    // 単一のコンポーネントを遅延読み込みする場合は loadComponent を使う
    loadComponent: () => import('./settings/settings.component').then(m => m.SettingsComponent),
  },
];

loadChildren・loadComponentに渡したimport()は、通常のJavaScriptの動的インポート構文です。

Angular CLIのビルドツール(esbuild)がこれを検知し、admin関連のコードを別ファイル(チャンク)として分割してビルドします。

管理画面のような「一部のユーザーしか使わない機能」を遅延読み込みにすることで、一般ユーザーの初期表示速度を大きく改善できます。

使用場面のまとめ

技術要素 使用場面
基本のルート設定 どのURLでどのコンポーネントを表示するかの対応付け
ルートパラメータ 商品詳細ページ・ユーザープロフィールなど、IDに応じて内容が変わる画面
Route Guard ログイン必須ページの保護、権限に応じたアクセス制御
Resolver 画面表示前にデータを揃えておきたい場合(ローディング表示を減らしたい場合)
遅延読み込み 管理画面など、一部のユーザーしか使わない機能の初期表示速度改善

まとめ

用語 役割
Router URLとコンポーネントの対応関係を管理する、Angular標準機能
<router-outlet> 現在のルートに対応するコンポーネントが描画される場所
Route Guard 特定のルートへの遷移を許可するか判定する仕組み
Resolver ルート遷移前に必要なデータを事前取得する仕組み
Lazy Loading 特定ルートに必要なコードを、実際にアクセスされるまで読み込まない仕組み

次回は、サーバーとの通信を担うHttpClientとRxJSについて解説します。

学習に使った書籍

本記事の内容整理にあたっても、以下の書籍を参考にしました。

※上記リンクはアフィリエイトリンクを含みます。

参考

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?