Angularの状態管理ライブラリ 「NGXS」に入門する

Kana Otawara
nextbeat-engineering
9 min readMar 26, 2019

こんにちは!今年1月より入社しました、開発グループの太田原です。

私は現在、保育園向け業務支援サービス「KIDSNA キズナコネクト」の開発チームに所属しています。
KIDSNA キズナコネクトは園長先生や保育士さんの業務負荷を軽減するシステムであり、労務管理保育料金管理などのバックオフィス系の機能に強みを持っています。

今回は、KIDSNA キズナコネクトにて使用しているAngularの状態管理ライブラリ「NGXS」について紹介したいと思います。

素敵なライブラリなのですが、まだまだ日本語情報がなく、私のような初心者(これまで業務でJavaScriptフレームワークを使ったこともなく、ましてや状態管理?Redux?Observable?なにそれ???な状態だった)にはとっつきづらいと感じたので、日本語の記事を書こうと思いました!

この記事では、Angular公式チュートリアルの「ツアー・オブ・ヒーローズ」をNGXSで状態管理したコードを見ながら、NGXS公式ドキュメントを解読していきます。また、NgRxとの違いについても調べてみます。

NGXSとは?

公式ドキュメント:https://ngxs.gitbook.io/ngxs

Angularの状態管理ライブラリとしては現在NgRx(NGXSと名前がすごく似ていますね!)がデファクトスタンダードだと思われます。

そんな中、NGXSは、NgRxやReduxに採用されている「CQRSパターン」を原型としつつ、ボイラープレートコードを削減しており、より簡潔に書くことができるのが強みらしいです!
(参考:https://ngxs.gitbook.io/ngxs/getting-started/why

とは言っても、初心者にはよくわからない・・・なので、

作ってみよう

早速ですが、Angular公式チュートリアルの「ツアー・オブ・ヒーローズ」をNGXSで状態管理するように書き換えてみます。

NGXSのインストール

こちらにあるようにnpmまたはyarnで「@ngxs/store」パッケージをインストールします。

プラグインもいろいろありますが、「NGXS Logger-plugin」を入れておくとActionごとの状態変化をコンソールで見ることができるので便利です!

NGXS Logger-pluginで状態変化を可視化

ツアー・オブ・ヒーローズにNGXSを適用

以下がツアー・オブ・ヒーローズにNGXSを適用したコードです。

また、以下がデモ環境(StackBlitz)です!

https://stackblitz.com/github/knts0/ngxs-tour-of-heroes

NGXS 4つの概念

サンプルアプリを見ながら、公式ドキュメントで紹介されているNGXSの4つの概念について理解していきます。
説明の都合上、公式ドキュメントと順番を変え、Action→State→Select→Storeとします。
これらは以下の図のような関係があります。StateはStoreが持っているイメージです。

https://ngxs.gitbook.io/ngxs/concepts/intro

Action

Actionは、アプリケーションの状態に変化を与えるものです。

今回、hero.actions.tsには以下のようなActionsを定義しています。各クラスのtypeフィールドがActionの識別子になっています。また、constructorに宣言しているフィールドは、各Actionに関連するメタデータを持たせるためのものです。

hero.actions.ts

State

Stateは、NGXSで管理したいアプリケーションの状態の定義と、Actionのマッピングを行うクラスです。
(NgRxの「Reducers」「Effects」「Selectors」を組み合わせたようなものです。)

今回は、以下の値の状態を管理したいです。

  • selectedHero(現在選択中のヒーロー)
  • heroes(全ヒーローのリスト)

これらをHeroStateModelクラスのフィールドとします。そして、@Stateデコレータをつけた箇所でStateのメタデータを定義します。

hero.state.ts

また、Stateクラスでは、各Actionに対応する処理を定義します。

例えば、HeroAction.Addについては@Action(HeroAction.Add)デコレータのついたaddHeroメソッドでハンドリングされます。

このメソッドではStateContext<HeroStateModel>型の「ctx」を引数に取っていますが、これは状態へのポインタと状態を変化させる機能を持っています。(以下では使用していませんが、StateContext#getStateメソッドで最新の状態を取得できます。)

addHeroメソッドでは、サーバーに新しいヒーローを追加する処理が実行されます。(Actionのメタデータはaction.payloadとして取り出しています。)

hero.state.ts

追加後はHeroAction.Loadがdispatchされ、@Action(HeroAction.Load)デコレータのついたloadメソッドでハンドリングされます。サーバーからヒーロー一覧を取得し、状態の更新が行われます。

StateContext#patchState は状態更新を簡潔に書けるメソッドです。(ここでは、HeroStateModelで更新のあるheroesプロパティのみ渡すことで、selectedHeroは値を変化させないようにしています。)

以上のように、NGXSではStateContextを用いることでStateクラス内で状態更新ロジックを書くことができます。NgRxのように、状態更新ロジックをReducerに切り出して記述しなくてもよくなります。

Select

SelectはStateの一部を読み出す機能です。これを使用するには以下の2つの方法があります。

  1. Storeサービスのselect メソッドを呼び出す
  2. @Selectデコレータを使用する

1つ目についてはStoreで説明するため、ここでは2つ目について見ていきます。例えば、hero.state.tsでは以下のように、HeroStateModelのうちの「heroes」プロパティのみを取り出すためのSelectorを宣言しています。

hero.state.ts

上記SelectorはDashBoardComponentで以下のように呼び出しています。これにより、Component内でObservableとして値を読み出すことができます。

dashboard.component.ts

Store

Storeは、Stateで定義した状態を保持し、各Componentと「Actions」を繋ぎ合わせたり、各ComponentにSelectorを提供します。
Componentで使用する際は以下のようにDIします。

以下、Storeの主な役割を説明していきます。

  • 状態を保持する

アプリケーション内全ての、Stateクラスで定義された状態を保持しています。(今回については、HeroStateModelクラスで定義したもののみ)

  • Actionをdispatchする

Actionのdispatchとは、実行するActionを指示することです。
例えば、HeroesComponentでは以下のようにHeroAction.Addをdispatchします。(引数「hero」はActionのところで説明したconstructorのフィールドに代入されます。)

heroes.component.ts

dispatchされると、Actionの説明のところで見たとおり、Stateクラスにおいて対応するメソッドが実行されます。

  • SelectorをComponentに提供する

今回のアプリケーションでは使用していませんが、Store#selectメソッドを呼び出すことで、動的にStateの一部を読み出すことができます。@Selectデコレータによる静的なSelectorの宣言が必要ない場面などで有用です。

(参考:https://ngxs.gitbook.io/ngxs/concepts/select#store-select-function

まとめ

まだまだ理解が浅いため、記述が誤っているところや、アドバイス等あればよろしくお願いいたします。

今回はツアー・オブ・ヒーローズの実装のために必要な機能の紹介にとどまりましたが、公式ドキュメントを見てみると他にもできることがたくさんあるのがわかります。これからどんどん詳しくなっていきたいです。

また、今後、日本語の情報が増えていくといいですね…!

告知

隔週木曜日に恵比寿のオフィスで夜活(交流会)を実施しています。
転職希望ではなくても、あるいはエンジニアでなくても、当社にご興味をお持ちの方は是非遊びに来てください!
綺麗なオフィスで軽食とお酒を楽しみましょう!

--

--