Angular コンポーネントから Route 特有のコードを綺麗にする
2018年4月12日木曜日
この記事は David East、デベロッパー アドボケートによる The Firebase Blog の記事 "Cleanse your Angular components of Route specific code" を元に翻訳・加筆したものです。詳しくは元記事をご覧ください。
認証コンポーネントを構築するとき、ストレスを感じることがよくあります。非同期フローは管理しにくく、テンプレートは ngIf と Elvis 演算子で乱雑になってしまいます。
ここで問題になることは、いつも同じです。あまりにも多くのことを 1 か所に詰め込みすぎているのです。適切なコードを適切な場所に配置するように整理すれば、快適なコードベースにすることができます。
解決策: ルーティング特有のコードは、Angular の Route Guard に保存します。
単純な
この例で行っているのは、以下の内容です。
コンポーネントが 1 つだけの場合、これでも問題はありません。しかし、複数のコンポーネントでリダイレクトを管理しなければならない場合を考えてみてください。
Route Guard には、さまざまな便利な使い方があります。今回は、リダイレクトのコードを扱います。
これで、コードを再利用できるようになります。Angular の Router を使うと、リッスンしてリダイレクトするルートを指定できます。
これで、
非同期フローで乱雑になることはもうありません。適切なコードが適切な場所に配置されるように整理されたのです。アプリの拡大に合わせて、
Reviewed by Yoshifumi Yamaguchi - Developer Relations Team
認証コンポーネントを構築するとき、ストレスを感じることがよくあります。非同期フローは管理しにくく、テンプレートは ngIf と Elvis 演算子で乱雑になってしまいます。
{{ (user | async)?.uid }}
ここで問題になることは、いつも同じです。あまりにも多くのことを 1 か所に詰め込みすぎているのです。適切なコードを適切な場所に配置するように整理すれば、快適なコードベースにすることができます。
解決策: ルーティング特有のコードは、Angular の Route Guard に保存します。
ステップ 1: コンポーネントの Route コードを特定する
AngularFireAuth サービスは、ルーティングのコードとの相性が抜群です。この中には、現在のユーザーについての情報や、リダイレクトされたのかどうかなど、あらゆる情報が含まれています。
単純な
signInWithRedirect の例を見てみましょう。
import { Component, OnInit } from '@angular/core';
import { AngularFireAuth } from 'angularfire2/auth';
import { Router } from '@angular/router';
import * as firebase from 'firebase/app';
@Component({
selector: 'app-login',
template: `
<button class="btn" (click)="auth()">
Login
</button>
`,
styleUrls: ['./login.scss']
})
export class LoginComponent implements OnInit {
constructor(
private afAuth: AngularFireAuth,
private router: Router
) { }
ngOnInit() {
this.afAuth.getRedirectResult().then(result => {
if(result) {
this.router.navigateByUrl('profile');
}
});
}
auth() {
const provider = new firebase.auth.GoogleAuthProvider();
this.afAuth.auth.signInWithRedirect(provider);
}
}
この例で行っているのは、以下の内容です。
- ユーザーが
auth()メソッドでログインします。 - Google でログインを行うため、
signInWithRedirect()メソッドによってリダイレクトがトリガーされます。 - アカウントを選択すると、ユーザーはこのコンポーネントに戻されます。
- ユーザーのログインは、
ngOnInit()内のgetRedirectResult()で返される Promise によって解決されます。 navigateByUrl()メソッドで、ルーターがユーザーをプロフィール ページに移動させます。
コンポーネントが 1 つだけの場合、これでも問題はありません。しかし、複数のコンポーネントでリダイレクトを管理しなければならない場合を考えてみてください。
ngOnInit のコードは、Route Guard に移すことができます。そうすると、ルーティング ロジックのコンポーネントを整理でき、Router への依存性を完全に削除することができます。
ステップ 2: Route Guard の作成
Route Guard には、さまざまな便利な使い方があります。今回は、リダイレクトのコードを扱います。
@Injectable()
export class RedirectGuard implements CanActivate {
constructor(
private authService: AngularFireAuth,
private router: Router
) {}
canActivate() {
this.authService.auth.getRedirectResult().then(result => {
if(result.user != null) {
this.router.navigateByUrl('profile');
return false;
}
return true;
});
}
}
canActivate メソッドは、ユーザーがルートにアクセスできるかを判定します。実際には、次のような処理が行われます。
- ユーザーがルートを開く。
AngularFireAuthが、リダイレクト結果が存在するかどうかを確認する。- ユーザーがリダイレクトから戻ってきた場合、
'profile'ルートにルーティングする。 - そうでない場合、現在のルートに移動する。
これで、コードを再利用できるようになります。Angular の Router を使うと、リッスンしてリダイレクトするルートを指定できます。
import { Routes, RouterModule } from '@angular/router';
import { LoginComponent } from './login/login.component';
import { RedirectGuard } from './redirect.guard';
const ROUTES: Routes = [
{
path: '',
component: LoginComponent,
canActivate: [RedirectGuard]
},
{
path: 'profile',
loadChildren: 'app/profile/profile.module#ProfileModule'
}
];
const AppRoutes = RouterModule.forRoot(ROUTES);
export { AppRoutes }
これで、
LoginComponent からルーティングのコードをなくすことができます。
@Component({
selector: 'app-login',
template: `
<button class="btn" (click)="auth()">
Login
</button>
`,
styleUrls: ['./login.scss']
})
export class LoginComponent {
constructor(private afAuth: AngularFireAuth) { }
auth() {
const provider = new firebase.auth.GoogleAuthProvider();
this.afAuth.auth.signInWithRedirect(provider);
}
}
非同期フローで乱雑になることはもうありません。適切なコードが適切な場所に配置されるように整理されたのです。アプリの拡大に合わせて、
RedirectGuard に他のルートを追加することもできます。これでコンポーネントが複雑にならずにすみます。
Reviewed by Yoshifumi Yamaguchi - Developer Relations Team