Angular状態管理: プロジェクトを進めるためのベスト プラクティス
効果的なAngular国家管理のための最良の戦略と実践にはどのようなものがありますか?こちらをご覧になり、アプリのパフォーマンスを向上させる方法をご確認ください。
大量のデータ通信を使用するAngularアプリを構築する場合は、データ効率、ネットワーク遅延、スケーラビリティ、リソース管理、テスト、UXなどの要素に対処する包括的なアプローチを検討する必要があります。そして、アプリのスケーラビリティと一貫性を維持しながらデータの競合を回避するために非常に重要なことの1つは、効果的なAngular状態管理です。それがなければ、データはどこにでも存在してしまいます。
しかし、Angularにおけるステートマネジメントとは何であり、具体的にどのように処理されるべきでしょうか? Ignite UI for Angularを使用したAngular State Management のベスト プラクティスを掘り下げ、Rxjsを使用した Service Basic 実装と NgRxを使用した State Managementを使用してアプローチする方法を、基本的なコード例でサポートしながら見ていきます。
Try Ignite UI Angular For Free
Angularにおけるステートマネジメントとは
これは、Angularアプリケーションの状態を処理および維持するためのさまざまな手法と戦略を含むプロセスです。この場合、Web アプリケーションの状態とは、外部サービスからフェッチされ、アプリによって操作および表示されるデータを含む、アプリケーションで使用されるすべてのデータと、アプリケーションが特定のユーザーの正しい UI を構築するために作成、保存、および使用するすべてのデータを指します。
簡単に言えば、なぜAngularで状態管理が必要なのか疑問に思うかもしれません。新しいページや新機能、現在の状態を示すアプリ内の新しい UI (ユーザーがログインしているかどうかなど) ごとに、アプリの複雑さが増します。単純なアプリの範囲を超えると、状態管理の整理された方法を適用しないと、これらすべてを管理するのが難しくなります。Angularでこれを行う最も一般的な方法は、データを取得、共有、更新するだけでなく、クリーンでよく整理された方法でデータにアクセスし、操作し、さらに変更できるようにする状態コンテナです。
電話をかける、または必要なタイミングを知る
アプリケーションの規模が拡大し、複雑になるにつれて、通常は大量のデータを処理することになり、大規模なプロジェクトでのデータ管理が難しくなることがあります。ここでは、非同期データ、追跡するデータ変更、コードなどを扱うと、事態はさらに複雑になります。絶え間ない変更コンピューティング、リフロー、APIリクエストなど、舞台裏であまりにも多くのことが進行し、ブラウザのメインスレッドがブロックされ、アプリが応答しなくなる可能性があります。国家管理に体系的に取り組まなければ、上記はバグや技術的負債などを修正するための多額の費用を意味します。
では、ステートマネジメントAngularをいつ使用するのでしょうか?ここでは、いくつかのユースケースをご紹介します。
- アプリケーションの複雑化
データフローが最小限のシンプルなアプリでは状態管理は必要ないかもしれませんが、複数のコンポーネント、多くのデータインタラクション、増え続ける機能セット、複雑なユーザーインターフェースを持つ大規模なソフトウェアプロジェクトでは特に有益です。
ここで達成されたこと:秩序、データの一貫性、パフォーマンスの向上、UXの向上+レスポンシブなインターフェースの提供。
- Sharing data
状態管理は、コンポーネントやサービスなど、アプリケーションのさまざまな部分間でデータを共有する必要がある場合に不可欠になります。
ここで実現されるのは、データの一元管理とデータ共有の簡素化です。
- 非同期操作
アプリに非同期操作 (API からのデータの取得、リアルタイム更新の処理、ユーザー操作の処理など) が含まれる場合。
ここで達成されたこと:合理化された非同期データフローとレスポンシブなUI。
- 予測可能な状態変化を目指す場合
Angularアプリケーションの状態がいつどのように変化するかを厳密に制御する必要がありますか?プロセスを容易にするさまざまな状態管理ライブラリがあります。
ここで達成されたこと:予測可能でデバッグが容易なコードベースを確保します。
開発者の作業を容易にする: Ignite UIによるAngular状態管理のベスト プラクティス
Angularで状態を管理する方法については、アプリの複雑さ、プロジェクトの要件、および知識と好みに応じて、さまざまな手法とツールがあります。たとえば、状態が 1 つのコンポーネントに固有である場合は、コンポーネント自体内でAngular状態で状態を管理できます。ここでデータを保存および更新するには、クラスのプロパティと変数に依存する必要があります。大規模なアプリケーションの場合は、状態管理ライブラリの使用を検討することをお勧めします。
しかし、これを詳しく見て、最適なAngular状態管理手法を探ってみましょう。
- 状態を管理するための優れた方法としてRxjsを利用したサービスの基本実装
サービスと RxJS を使用したAngularでの状態管理は強力で柔軟なアプローチであり、いくつかのベスト プラクティスを次に示します。
- Single responsibility principle
各サービスに 1 つの責任があることを確認します。特定のタスク(ユーザーのログ記録と認証、ユーザーデータの管理など)を処理するようにサービスを設計することで、コードベースをクリーンで保守可能な状態に保つことができます。各サービスは、デバッグとテストを容易にするために、状態の特定の部分を管理する必要があります。
- 信頼できる唯一の情報源としてのサービス
サービスを国家の信頼できる唯一の情報源として扱います。コンポーネントは、状態情報と更新をサービスに依存し、一方向のデータ フローを促進し、アプリケーションが推論しやすくする必要があります。
- サービスで状態ロジックをカプセル化する
状態ロジックは、コンポーネント内ではなく、サービス内に保持します。サービスはビジネス ロジックと状態管理を処理する必要がありますが、コンポーネントはプレゼンテーションと対話に重点を置いています。この懸念事項の分離により、テストの容易性と再利用性が向上します。
- Error handling
サービス内でエラー処理を実装します。オブザーバブルのエラーをキャッチして処理し、スムーズなユーザーエクスペリエンスを提供し、アプリケーションのクラッシュを防ぎます。
- RxJsのオペレーターと被験者を国家管理に活用する
そのためには、まず、適切なサブジェクト (基本的なマルチキャスト オブジェクト) を選択し、状態を保持せずに複数のサブスクライバーに値を出力します。イベントやアクションに適しています。次に、Behavior Subject を定義します。これは、初期値を必要とし、その現在の値を新しいサブスクライバーに出力するサブジェクトの一種です。これは、状態を初期化し、新しいサブスクライバーに常に最新の状態を提供できるため、状態管理に役立ちます。ReplaySubject: 指定された数の以前の値を新しいサブスクライバーに出力します。過去の状態値を再生する必要がある場合に便利です。次に、AsyncSubject を使用すると、完了時に最後の値 (最後の値のみ) を出力できます。これは、最終的に出力された値のみが必要なシナリオで役立ちます。
ステップ 2 として、複数のステートストリームを使用できます。combineLatest、withLatestFromなどの RxJS 演算子を使用して、複数のステート ストリームを結合します。多くの場合、複数の観測量に基づいて状態を導出する必要があります。combineLatestのような演算子を使用すると、他のステートストリームの組み合わせに基づいて新しいステートオブザーバブルを作成できます。次に、サービスとその状態管理ロジックの単体テストを記述します。テストを通じてサービスが期待どおりに動作することを確認することは、アプリケーションの安定性を維持し、問題を早期に発見するために重要です。
サービスを使用すると、気象データを取得して保存するためのロジックを一元化できます。これにより、気象データを必要とするすべてのコンポーネントが、信頼できる唯一の情報源からデータを取得できるようになります。
ウェザーサービス
interface WeatherData {
temperature: number;
description: string;
}
@Injectable({
providedIn: 'root'
})
export class WeatherService {
private apiKey = 'YOUR_API_KEY';
private _weather: BehaviorSubject<WeatherData | null> = new BehaviorSubject<WeatherData | null>(null);
public weather$: Observable<WeatherData | null> = this._weather.asObservable();
constructor(private http: HttpClient) { }
private getApiUrl(location: string): string {
return `https://api.weatherapi.com/v1/current.json?key=${this.apiKey}&q=${location}`;
}
fetchWeather(location: string): Observable<WeatherData | null> {
const apiUrl = this.getApiUrl(location);
return this.http.get<WeatherData>(apiUrl).pipe(
tap((data: WeatherData) => this._weather.next(data)),
catchError(error => {
console.error('Error fetching weather data', error);
this._weather.next(null);
return of(null);
})
);
}
}
'WeatherService'はAPIからデータを取得し、それを'BehaviorSubject'に格納し、サービスを挿入する任意のコンポーネントからアクセスできるようにします。rxjsの「BehaviorSubject」を使用します。アプリケーションによるデータ変更の事後対応管理が可能になります。サービスで気象データが更新されると、「BehaviorSubject」にサブスクライブしているすべてのコンポーネントに自動的に通知され、それに応じてビューを更新できます。
Component TS file:
export class WeatherDisplayComponent implements OnInit {
weather$: Observable<WeatherData | null>;
constructor(private weatherService: WeatherService) {
this.weather$ =this.weatherService.weather$;
}
ngOnInit(): void {
this.weatherService.fetchWeather('New York');
}
}
コンポーネント HTML ファイル:
<div *ngIf="weather$ | async as weather">
<h2>Current Weather</h2>
<p>Temperature: {{ weather.temperature }}°C</p>
<p>Description: {{ weather.description }}</p>
</div>
コンポーネントは、データの取得や状態管理について心配することなく、データの表示とユーザー操作の処理に引き続き重点を置いています。このように懸念事項を分離することで、コンポーネントの記述、テスト、保守が容易になります。
次に、NgRx を使用した状態管理の例を示します。
Angularアプリケーションの状態管理に NgRx を使用すると、特に大規模で複雑なアプリケーションに対して、追加の利点が得られます。NgRxは、Reduxパターンを使用してAngularアプリケーションのリアクティブ状態を管理するためのライブラリです。
気象データの構造を定義します。
weather.model.ts
export interface WeatherData {
temperature: number;
description: string;
}
export interface WeatherState {
weather: WeatherData | null;
loading: boolean;
error: string | null;
}
天気予報機能のさまざまなイベントを表すアクションを定義します。
weather.actions.ts
export const loadWeather = createAction(
'[Weather] Load Weather',
props<{ location: string }>()
);
export const loadWeatherSuccess = createAction(
'[Weather] Load Weather Success',
props<{ weather: WeatherData }>()
);
export const loadWeatherFailure = createAction(
'[Weather] Load Weather Failure',
props<{ error: string }>()
);
アクションに基づいて状態の変化を処理するためのレデューサーを定義します
weather.reducer.ts
export const initialState: WeatherState = {
weather: null,
loading: false,
error: null,
};
export const weatherReducer = createReducer(
initialState,
on(loadWeather, (state) => ({
...state,
loading: true,
error: null,
})),
on(loadWeatherSuccess, (state, { weather }) => ({
...state,
weather,
loading: false,
})),
on(loadWeatherFailure, (state, { error }) => ({
...state,
loading: false,
error,
}))
);
副作用の処理 API 呼び出しなどの副作用の処理:
weather.effects.ts
@Injectable()
export class WeatherEffects {
loadWeather$ = createEffect(() =>
this.actions$.pipe(
ofType(loadWeather),
mergeMap(action => this.http.get<WeatherData>(`https://api.weatherapi.com/v1/current.json?key=YOUR_API_KEY&q=${action.location}`).pipe(
map(weather => loadWeatherSuccess({ weather })),
catchError(error => of(loadWeatherFailure({ error: error.message })))
)
))
);
constructor(private actions$: Actions, private http: HttpClient) { }
}
app.module.tsで、NgRx ストアとエフェクトを登録して、アプリケーション全体で使用できるようにします。
@NgModule({
imports: [
BrowserModule,
HttpClientModule,
StoreModule.forRoot({ weather: weatherReducer }),
EffectsModule.forRoot([WeatherEffects]),
]
})
気象の特徴の状態から状態の一部を派生させるための気象状態のセレクターを定義します。
weather.selectors.ts
export const selectWeatherState = createFeatureSelector<WeatherState>('weather');
export const selectWeather = createSelector(
selectWeatherState,
(state: WeatherState) => state.weather
);
export const selectLoading = createSelector(
selectWeatherState,
(state: WeatherState) => state.loading
);
export const selectError = createSelector(
selectWeatherState,
(state: WeatherState) => state.error
);
ストアをコンポーネントに挿入し、ディスパッチ アクションを実行して気象データを読み込み、表示する状態を選択します。
weather-display.component.ts
export class WeatherDisplayComponent implements OnInit {
weather$: Observable<WeatherData | null>;
loading$: Observable<boolean>;
error$: Observable<string | null>;
constructor(private store: Store<{ weather: WeatherState }>) {
this.weather$ = this.store.pipe(select(selectWeather));
this.loading$ = this.store.pipe(select(selectLoading));
this.error$ = this.store.pipe(select(selectError));
}
ngOnInit(): void {
this.store.dispatch(loadWeather({ location: 'New York' }));
}
}
コンポーネント HTML ファイル:
<div *ngIf="loading$ | async">Loading...</div>
<div *ngIf="error$ | async as error">{{ error }}</div>
<div *ngIf="weather$ | async as weather">
<h2>Current Weather</h2>
<p>Temperature: {{ weather.temperature }}°C</p>
<p>Description: {{ weather.description }}</p>
</div>
2. 状態管理ライブラリの使用を検討する – NgRx
NgRxは、リアクティブプログラミングの原則を使用してAngularアプリケーションの状態を管理するための強力なライブラリです。これはReduxパターンに触発され、Angularとうまく統合されているため、アプリケーションの状態の保守とデバッグが容易になります。

より明確にするために、ここでは主要な概念について説明します。
ストア– 一貫性のある状態管理を確保し、一方向のデータ フローを促進し、アプリケーションの状態を処理するための構造化された方法を提供します。これは、アプリケーション全体の状態を不変のオブジェクト ツリーとして表します。このツリーの各ノードは、オブザーバブルを介してアクセスされるアプリケーション状態の特定の部分に対応しており、コンポーネントは状態の特定のスライスをサブスクライブできます。
アクション– NgRx を利用したアプリケーションのイベントを記述します。これらは、アプリケーション内で発生したことを表しており、事実の記述と見なすことができます。
レデューサー– 現在の状態とアクションを受け取り、新しい状態を返す関数。レデューサーは、アクションに応答して状態がどのように変化するかを指定します。
セレクター– ストアから状態のスライスを選択するために使用される関数。これらは、状態構造のカプセル化に役立ち、より複雑なセレクターを作成するように構成できます。
エフェクト– 副作用はストアの外で処理されます。エフェクトは、特定のアクションをリッスンし、API 呼び出しなどのタスクを実行し、結果に基づいて新しいアクションをディスパッチするクラスです。Angular Dependency Injectionを使用し、RxJSオブザーバブルを活用して副作用を管理します。
NgRxを使用する際の簡単なヒントとコツ
まず、状態を整理し、特徴状態の分離を実行します。これを行うには、機能モジュールごとに状態を分離します。各機能モジュールには、モジュール化と保守性を維持するために、独自の状態スライスが必要です。各機能モジュール内で、アクション、レデューサー、セレクター、エフェクトなど、一貫したフォルダー構造を使用します。
その後、明確なアクションタイプを定義できます。アクションの命名については、説明的なアクションタイプを使用します。アクションタイプには、それらが属する機能の前に付けます(例:「[Weather] Load Weather」)。アクションペイロードには、厳密に型指定されたペイロードを使用します。また、ペイロードのインターフェースを定義して、タイプ セーフを確保する必要があります。NgRxに関してもう一つ重要なことは、純粋なレデューサーを書くことです。レデューサーが純粋な関数であることを常に確認し、既存の状態を変更するのではなく、常に新しい状態オブジェクトを返します。また、レデューサーのロジックは最小限に抑えます。レデューサーの副作用や複雑なロジックを避けてください。それらを効果に委任します。
ステートアクセスにセレクターを使用することも考慮すべき点です。セレクターを使用して、状態構造をカプセル化できます。これにより、コンポーネント コードをクリーンに保ち、状態の形状を抽象化できます。または、セレクターを作成して、より複雑な状態選択を作成することもできます。重要なことは、エフェクトを使用して API 呼び出し、ログ記録などの副作用を処理することです。これにより、減速機の純度が保たれ、コンポーネントが清潔に保たれます。また、エフェクトのエラーは常に処理する必要があることを覚えておいてください。適切なアクションを使用して、エラー状態を管理します。
最後に、テストに関して注意すべき点がいくつかあります。レデューサーの単体テストを記述して、特定のアクションに対して正しい状態を返すことを確認します。エフェクトをテストして、正しいアクションをディスパッチし、副作用を適切に処理することを確認します。「MockStore」を使用して、実際のNgRxストアから分離してコンポーネントをテストすることをお勧めします。
これをAngular State Managementの例でより鮮明に示しましょう。
天気予報アプリを作成していると想像してください。その中で、APIから天気予報に関するデータを取得し、それをアプリケーションのさまざまな部分に表示する必要があります。これを行うには、API 要求を処理し、指定されたデータを格納するAngularで WeatherService を作成できます。このサービスをさまざまなコンポーネントに注入して、天気情報にアクセスして表示できます。
まとめ
結論として、RxJS と NgRx と共にサービスを使用したAngularアプリケーション向けのこれらの状態管理手法には、プロジェクトの要件とチームの専門知識に基づいて慎重に検討する必要がある独自の利点とトレードオフがあります。最終的には、プロジェクトの特定の要件、開発の制約、チームの能力を優先して決定する必要があります。これらの要素を慎重に評価することで、開発者は目標に最も適した状態管理アプローチを選択し、Angularアプリケーションを正常に提供できます。
