以前、会社のテックブログにNGXSに関する記事を書いたことがあり、
Angularの状態管理ライブラリ 「NGXS」に入門する | by Kana Otawara | nextbeat-engineering | Medium
その際に割と真剣にドキュメントを読んだのですが、それから1年以上経過してまた読んでみました。
いろいろと更新されていたり、1年ほど実務で開発経験を積んだ状態で読んだこともあり、これを知ってると役立ちそうだなと思ったこともあったのでまとめてみます。
※本記事では NGXSドキュメント Concepts - NGXS 配下のページ を対象とします。(2020/07/27時点の内容)
Store
リンク:https://www.ngxs.io/concepts/store
同時に複数のActionをdispatchできる!
this.store.dispatch([new AddAnimal('Panda'), new AddAnimal('Zebra')]);
これは完全に初知りでした。
Actions
リンク:https://www.ngxs.io/concepts/actions
Actionの名前付け方法のおすすめが載っている
https://www.ngxs.io/concepts/actions#how-should-you-name-your-actions
こちらのセクションです。
動詞+目的語、みたいな付け方はすでにしていますが、それにプラスしてコンテキストを書いておくといいよ〜みたいなことを書いてあります。なるほどなぁ
Action定義のグループ化ができる!
TodoAction
, TodoEdit
・・・みたいに定義しなくてもスッキリと。
export namespace Todo {
export class Add {
static readonly type = '[Todo] Add';
constructor(public payload: any) {}
}
export class Edit {
static readonly type = '[Todo] Edit';
constructor(public payload: any) {}
}
export class FetchAll {
static readonly type = '[Todo] Fetch All';
}
export class Delete {
static readonly type = '[Todo] Delete';
constructor(public id: number) {}
}
}
State
リンク:https://www.ngxs.io/concepts/state
サブstateを指定できる!
Stateのメタデータ定義の際に、children
という任意の属性の中に他のStateの配列を指定すると、サブStateにすることができます。
import { Injectable } from '@angular/core';
import { State } from '@ngxs/store';
export interface SampleStateModel {
hoge: string;
}
@State<SampleStateModel>({
hoge: 'test',
defaults: {
hoge: null
},
children: [AnotherState]
})
@Injectable()
export class SampleState {}
これは「Advanced」の方で取り上げられています。(詳しく読んでみたいものです。)
https://www.ngxs.io/advanced/sub-states
複数のActionをlistenできる!
これは実は私個人は知ってたんですが、意外と知らない方もいるのではないかと勝手に思っています。
dispatchのときと同様に、複数のActionをlistenできます。
@Action([FirstAction, SecondAction])
doSomething(ctx: StateContext<SampleStateModel>) {
...
}
Select
リンク:https://www.ngxs.io/concepts/select
Selectの定義の仕方はかなりいろいろある
そもそもtipsでもなんでもないのですが、Selectはかなりいろいろな方法で定義や生成ができるので、このページを一度読んでみるといろいろな発見があります。
selectSnapshotによりObservableに包まれない状態でその瞬間の値を得ることができる!
これも実は私個人は知ってたんですが・・・Observableを使えない場面で便利です。(例えばその瞬間は絶対に値が何かしら設定されていることが保証されていて、Observableに包まれない状態で取得して扱いたい場合などです。)
const hogeValue: string = this.store.selectSnapshot<string>((state: SampleState) => state.hoge);
Selectorの継承
これも似たようなコードが大量発生する場合に実務上で役に立ちそうだと感じました。
実際に実務で、
APIでサーバから何かしらの値の配列を取ってきて、Stateに
values
という属性に設定し、状態管理させる
みたいなことをたくさんのStateでやっているケースがあるのですが、以下のように親State
クラスを定義して継承することでスッキリとしそうです。
export class ParentState {
static values<T>() {
// Selectorを動的に生成する
return createSelector([this], (state: { values: T[] }) => {
return state.values;
});
}
//...
}
以下のように継承すると、FirstState.values
、SecondState.values
というSelectorが外部から使えるようになります。
// 子State 1
export interface FirstStateModel {
values: First[];
}
@State<FirstStateModel>({
name: 'first',
defaults: {
values: []
}
})
@Injectable()
export class FirstState extends ParentState {
//...
}
// 子State 2
export interface SecondStateModel {
values: Second[];
}
@State<SecondStateModel>({
name: 'second',
defaults: {
values: []
}
})
@Injectable()
export class SecondState extends ParentState {
//...
}
実際にコンポーネント等から呼ぶときは、以下のような感じです。
@Select(FirstState.values<First>())
firstValues$: Observable<First[]>;
@Select(SecondState.values<Second>())
secondValues$: Observable<Second[]>;
TODO
ドキュメント読んでいると他にもいろいろ興味深いことがあるので、深堀りしたいところです。
特に非同期のActionsについてや、いろんなSelectorなどなど・・・
参考
NGXS公式ドキュメント https://www.ngxs.io/