【Angular】NgRxで状態管理を実装する方法

当ページのリンクには広告が含まれています。
いずみ

こんな悩みを解決できる記事を書きました!

僕は現役フリーランスエンジニア(歴年)で、資格は個保有しています。

AngularでNgRxを使った状態管理を実装する方法を知りたい」とお考えではありませんか?

Angularアプリの規模が大きくなり、コンポーネント間で状態を共有する処理が複雑になってきた方へ。

NgRxを使えば、アプリ全体の状態を1つのStoreにまとめて管理することが可能です。

いずみ

サクッと解説します。

ということで、本記事ではAngularでNgRxを使った状態管理を実装する方法を解説します。

いずみ

すぐ読み終わるので、ぜひ最後まで読んでくださいませ。

スクロールできます
【当サイト】おすすめフリーランスエージェント3選
エージェント評価ポイント公式サイト
レバテックフリーランス

5.0
業界最大級のエージェント。
高単価案件が豊富。
公式
Midworks

4.8
満足度調査で
3年連続3冠を達成。
公式
ITプロパートナーズ

4.6
週2〜3向けの案件が豊富。公式
執筆者/監修者
  • フリーランスエンジニア(保有資格個、企業と直接契約
  • ブログ・アフィリエイト歴7年(2018年〜)
  • ブランドせどりで月利50万円⇨脱サラ
  • 投資(仮想通貨・FX)歴7年(2018年〜)
  • X(旧Twitter)フォロワー約1,900人
  • 運営者情報はこちら
いずみです
目次

【Angular】NgRxで状態管理を実装する方法

早速ですが、AngularでNgRxを使った状態管理の実装方法を解説します。

NgRxとは

NgRxはReduxパターンをAngular向けに実装した状態管理ライブラリです。

Action・Reducer・Store・Selectorという4つの要素で構成されています。

コンポーネントがActionをdispatchすると、Reducerが新しい状態を計算してStoreを更新します。

コンポーネントはSelectorを通してStoreから必要な状態だけを取得します。

いずみ

Reduxを触ったことがある方なら、考え方はほぼ同じなので理解しやすいと思います。

NgRxをインストールする

まずは、NgRxをインストールします。

STEP
パッケージをインストールする

npmコマンドで@ngrx/store・@ngrx/effects・@ngrx/store-devtoolsをインストールします。

npm install @ngrx/store @ngrx/effects @ngrx/store-devtools
STEP
Storeをapp.config.tsに登録する

provideStoreをapp.config.tsのprovidersに追加します。

import { ApplicationConfig } from '@angular/core';
import { provideStore } from '@ngrx/store';
import { provideEffects } from '@ngrx/effects';
import { provideStoreDevtools } from '@ngrx/store-devtools';

export const appConfig: ApplicationConfig = {
  providers: [
    provideStore(),
    provideEffects(),
    provideStoreDevtools({ maxAge: 25 }),
  ],
};

provideStoreDevtoolsを追加しておくと、ブラウザ拡張機能のNgRx DevToolsで状態の変化を確認できます。

Actionを定義する

次に、状態を変更するきっかけとなるActionを定義します。

createActionGroupを使うと、関連するActionをまとめて1つのオブジェクトとして定義できます。

import { createActionGroup, emptyProps, props } from '@ngrx/store';
import { Todo } from './todo.model';

export const TodosActions = createActionGroup({
  source: 'Todos',
  events: {
    'Load Todos': emptyProps(),
    'Load Todos Success': props<{ todos: Todo[] }>(),
    'Load Todos Failure': props<{ error: string }>(),
    'Add Todo': props<{ title: string }>(),
  },
});
いずみ

イベント名を文字列で書くだけで、キャメルケースのActionクリエイターが自動生成されるので、命名の重複を防げます。

Reducerを定義する

続いて、Actionを受け取って状態を更新するReducerを定義します。

createFeatureを使うと、Reducerの定義と同時にSelectorも自動生成されます。

import { createFeature, createReducer, on } from '@ngrx/store';
import { TodosActions } from './todos.actions';
import { Todo } from './todo.model';

interface TodosState {
  todos: Todo[];
  loading: boolean;
  error: string | null;
}

const initialState: TodosState = {
  todos: [],
  loading: false,
  error: null,
};

export const todosFeature = createFeature({
  name: 'todos',
  reducer: createReducer(
    initialState,
    on(TodosActions.loadTodos, (state) => ({ ...state, loading: true })),
    on(TodosActions.loadTodosSuccess, (state, { todos }) => ({
      ...state,
      todos,
      loading: false,
    })),
    on(TodosActions.loadTodosFailure, (state, { error }) => ({
      ...state,
      error,
      loading: false,
    })),
    on(TodosActions.addTodo, (state, { title }) => ({
      ...state,
      todos: [...state.todos, { id: Date.now(), title, done: false }],
    })),
  ),
});

onの第1引数に対象のActionを、第2引数に状態を更新する関数を渡します。

Storeにfeatureを登録する

定義したtodosFeatureを、app.config.tsのprovidersにprovideStateで登録します。

providers: [
  provideStore(),
  provideState(todosFeature),
  provideEffects(TodosEffects),
],

provideEffectsにTodosEffectsを渡して、後述する非同期処理も同時に登録します。

コンポーネントから状態を利用する

コンポーネント側では、Storeをinjectして状態の取得とActionのdispatchを行います。

import { Component, inject } from '@angular/core';
import { Store } from '@ngrx/store';
import { todosFeature } from './todos.reducer';
import { TodosActions } from './todos.actions';

@Component({
  selector: 'app-todo-list',
  standalone: true,
  templateUrl: './todo-list.component.html',
})
export class TodoListComponent {
  private store = inject(Store);

  todos = this.store.selectSignal(todosFeature.selectTodos);
  loading = this.store.selectSignal(todosFeature.selectLoading);

  constructor() {
    this.store.dispatch(TodosActions.loadTodos());
  }

  addTodo(title: string) {
    this.store.dispatch(TodosActions.addTodo({ title }));
  }
}

selectSignalを使うと、Selectorの結果をAngular Signalとしてテンプレートで直接扱えます。

いずみ

selectSignalのおかげで、async pipeを使わずにテンプレート内で状態を表示できるようになりました。

非同期処理をEffectsで実装する

APIからデータを取得するような非同期処理は、Effectsに切り出します。

import { Injectable, inject } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { catchError, map, of, switchMap } from 'rxjs';
import { TodosActions } from './todos.actions';
import { TodoService } from './todo.service';

@Injectable()
export class TodosEffects {
  private actions$ = inject(Actions);
  private todoService = inject(TodoService);

  loadTodos$ = createEffect(() =>
    this.actions$.pipe(
      ofType(TodosActions.loadTodos),
      switchMap(() =>
        this.todoService.getTodos().pipe(
          map((todos) => TodosActions.loadTodosSuccess({ todos })),
          catchError((error) => of(TodosActions.loadTodosFailure({ error: error.message }))),
        ),
      ),
    ),
  );
}

createEffectの中でActionを監視し、APIの結果に応じて成功または失敗のActionをdispatchします。

いずみ

EffectsにAPI通信をまとめておくと、コンポーネントとReducerはAPIの存在を意識しなくて済むので、テストもしやすくなります。

スクロールできます
【当サイト】おすすめフリーランスエージェント3選
エージェント評価ポイント公式サイト
レバテックフリーランス

5.0
業界最大級のエージェント。
高単価案件が豊富。
公式
Midworks

4.8
満足度調査で
3年連続3冠を達成。
公式
ITプロパートナーズ

4.6
週2〜3向けの案件が豊富。公式

【厳選】フリーランスエンジニアにおすすめなエージェント3選

フリーランスエンジニアになるにはエージェントから案件をもらう必要があります。

僕が実際に利用しているおすすめエージェントを紹介しますね。

いずみ

エージェントは必ず複数登録してください。

担当者によっては「全然案件紹介してくれない…」みたいなこともあるので…

僕は実際に5つのエージェントを使い回していますよ。

フリーランスを始めるなら「

案件数マージン率単価
約88,000件非公開
初心者福利厚生申し込み
無料
Good Point
  • 業界最大級の案件数。
  • 業界トップクラスの高単価報酬、低マージン(平均年収862万円)。
  • 案件参画中のフォローの充実。

※詳細は「【業界最大手】レバテックフリーランスとは?メリットや利用手順を解説!」を参照。

は業界最大手のフリーランスエージェントです。

とにかく案件数が多いので、とりあえず登録しておけば間違いないエージェントです!

いずみ

僕もはじめてフリーランスの案件を貰ったのはです。

保有している案件数が多いので、業務経験がなくても何かしらの案件は紹介してもらえますよ(僕はJavaの経験3年でも案件を貰えました)。

手厚い保障を重視したいなら「

案件数マージン率単価
約10,000件非公開
初心者福利厚生申し込み
無料
Good Point
  • 手厚い保障で正社員並みの安心感。
  • 還元率60%超え&単価公開でクリアな契約。
  • 給与保障制度(審査あり)。

は手厚い保障が特徴のフリーランスエージェントです。

フリーランスを目指しているけど不安な方や保障を重視したい方におすすめです。

いずみ

僕も何度か案件を紹介してもらいました。

自分のスキルに合った案件を紹介してもらえましたし、電話のやり取りも非常に丁寧でした。

週2〜3日の案件探しなら「

案件数マージン率単価
約5,000件非公開
初心者福利厚生申し込み
経験者向け無料
Good Point
  • IT案件に特化したフリーランスエージェント。
  • 週2〜3日の案件が豊富。
  • リモート案件が多く、直エンドなので単価も高い。

※詳細は「【週2・3案件】ITプロパートナーズとは?メリットや利用手順を解説!」を参照。

はIT案件に特化したフリーランスエージェントです。

週2〜3日から参画できる案件が豊富なので、起業したい人にもおすすめです。

いずみ

週2〜3日の案件はある程度スキルがないと紹介してもらえない印象です。

とはいえ、週5の案件ももちろんありますし、僕が利用した時は迅速・丁寧に対応していただきました!

よくある質問

NgRxとAngular Signalsはどちらを使うべきですか?

コンポーネント単体やごく限られた範囲で完結する状態であれば、Angular Signalsだけで十分管理できます。

複数の離れたコンポーネントで同じ状態を共有したり、状態の変化履歴をNgRx DevToolsで追いたい場合は、NgRxの導入を検討すると良いです。

createActionGroupを使うメリットは何ですか?

イベント名の重複を防ぎつつ、キャメルケースのActionクリエイターを自動生成してくれます。

個別にcreateActionを書くよりもコード量が減り、関連するActionが1つのオブジェクトにまとまるので見通しも良くなります。

NgRx DevToolsは必須ですか?

必須ではありませんが、開発中に導入しておくとdispatchされたActionと状態の変化を時系列で確認できます。

provideStoreDevtoolsをapp.config.tsに追加するだけで使えるようになります。

まとめ

今回は、AngularでNgRxを使った状態管理を実装する方法について解説しました。

以下が本記事のまとめになります。

まとめ
  • NgRxは ActionReducerStoreSelector で構成されるReduxパターンの状態管理ライブラリ。
  • createActionGroupcreateFeatureを使うと、Action・Reducer・Selectorを少ないコードで定義できる。
  • selectSignalを使えば、Storeの状態をAngular Signalとしてテンプレートで直接扱える。
まとめ
  • おすすめ本
¥4,070 (2023/07/23 15:56時点 | Amazon調べ)

Angularの勉強なら「」が分かりやすくておすすめですよ♪

いずみ

最後までお読みいただき、ありがとうございました!

スクロールできます
【当サイト】おすすめフリーランスエージェント3選
エージェント評価ポイント公式サイト
レバテックフリーランス

5.0
業界最大級のエージェント。
高単価案件が豊富。
公式
Midworks

4.8
満足度調査で
3年連続3冠を達成。
公式
ITプロパートナーズ

4.6
週2〜3向けの案件が豊富。公式
  • クソおすすめ本
¥4,480 (2024/06/01 23:28時点 | Amazon調べ)
いずみ

海外のエンジニアがどういった思考で働いているかが理解できます。

海外に行く気はないけど海外エンジニアの動向が気になる雑魚エンジニアにおすすめです(本当におすすめな本しか紹介しないのでご安心を)。

この記事が気に入ったら
フォローしてね!

シェアしてね!
  • URLをコピーしました!
目次