【Angular】AkitaのEntityStoreを使った状態管理

前回に引き続き状態管理ライブラリ「Akita」を使った状態管理について紹介していきます。
前回はデータをkey-valueで保持してくれる「Store」を使っていきましたが、今回はEntityを定義して、その配列のような形でデータを保持してくれる「EntityStore」を使っていきます。

スポンサーリンク

Akitaのインストール

Akitaを使う利点やインストール方法については以前書いたこちらの記事に詳しく載っているので、良ければ参照してください。
インストール方法をざっくり紹介していくと、コマンドプロンプトから以下2つのコマンドを実行してくれればできます。

npm install @datorama/akita
npm install @datorama/akita-cli -g

EntityStoreを作成する

EntityStoreを使うにあたって以下5つのファイルが必要になります。

  • index.ts:import用のBarrel
  • ○○○○.query.ts Storeのデータを読み込むのに使います。
  • ○○○○.service.ts Storeのデータを書き込むのに使います。
  • ○○○○.store.ts EntityのStoreを作ります。
  • ○○○○.model.ts Entityを定義します。

Akitaのコマンドを使うと、これら5つのファイルを一度に作れます。
コマンドプロンプトで「Akita」と入力してください。

> akita
Give me a name, please ringo
Which store do you need? EntityStore
Choose a directory.. (Use arrow keys)

Give me a name, please :EntityStoreの名前を入力してください。今回はringoにしました。
Which store do you need? :選択肢として「EntityStore」と「Store」が用意されています。今回はEntityStoreにします。
Choose a directory.. (Use arrow keys)  :どこのディレクトリに作るかを選択してください。こちらも選択肢が表れますので、そこから選んでください。

Modelの編集

Modelファイルを編集し、Entityを定義していきましょう

import { ID } from "@datorama/akita";

export interface Ringo {
    id: ID;
    name: string;
    counter: number;
}

今回はRingoというEntityを定義しました。IDと名前(name)、個数(counter)をプロパティとして用意します。

Storeの編集

import { Injectable } from '@angular/core';
import { EntityState, EntityStore, StoreConfig } from '@datorama/akita';
import { Ringo } from './ringo.model';

export interface RingoState extends EntityState<Ringo> {}

@Injectable({ providedIn: 'root' })
@StoreConfig({ name: 'ringo' })
export class RingoStore extends EntityStore<RingoState> {
  constructor() {
    super();
  }
}

ここでRingoStoreというものを定義していきます。このRingoStoreにRingoエンティティを追加して、複数のRingoエンティティを管理していくことになります。

Serviceの編集

import { Injectable } from '@angular/core';
import { guid, ID } from '@datorama/akita';
import { RingoStore } from './ringo.store';
@Injectable({ providedIn: 'root' })
export class RingoService {
  constructor(private ringoStore: RingoStore) {}

  addRingo(name: string, counter: number) {
      this.ringoStore.add({
      id: guid(),
      name: name,
      counter: counter
    });
  }

  deleteRingo(id: ID) {
    this.ringoStore.remove(id);
  }
}

Serviceを定義していきます。ここで定義したメソッドをもとに、RingoStoreにデータを入れたり削除したりすることになります。
今回は1個エンティティを追加するものと削除するものだけを用意しました。

Queryの編集

import { Injectable } from '@angular/core';
import { QueryEntity } from '@datorama/akita';
import { RingoState,RingoStore } from './ringo.store';

@Injectable({ providedIn: 'root' })
export class RingoQuery extends QueryEntity<RingoState> {
  constructor(protected ringo: RingoStore) {
    super(ringo);
  }
}

これを使うことでRingoStoreの内容を読み込んでいくことになります。

コンポーネントからEntityStoreを使っていく

では早速コンポーネントからEntityStoreを使っていきましょう。
HTMLとTSファイルをこのように定義してみました。

import { Component } from '@angular/core';
import { Observable } from 'rxjs';
import { RingoService } from './state/ringo.service';
import { RingoQuery } from './state/ringo.query';
import { RingoState } from './state/ringo.store';
import { getEntityType } from '@datorama/akita/src/lib/types';
import { FormControl, FormGroup } from '@angular/forms';
import { ID } from '@datorama/akita';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'angular-study';
  readonly Ringo$: Observable<getEntityType<RingoState>[]>;
  formGroup: FormGroup;

  constructor(
    private ringoService: RingoService,
    private ringoQuery: RingoQuery,
  ){ 
    this.Ringo$ = this.ringoQuery.selectAll();
    this.formGroup = new FormGroup({
      name: new FormControl(''),
      counter: new FormControl(0)
    });
  }

  addRingo() {
    this.ringoService.addRingo(this.formGroup.get('name')?.value, this.formGroup.get('counter')?.value);
  }

  deleteRingo(id:ID){
    this.ringoService.deleteRingo(id);
  }
}
<div>
    <form [formGroup]="formGroup" (ngSubmit)="addRingo()">
        <p>名前を設定する</p>
        <input type="text" formControlName="name">
        <p>個数を設定する</p>
        <input type="text" formControlName="counter">
        <input type="submit" value="追加">
    </form>
    <table>
        <tr>
            <th>ID</th>
            <th>名前</th>
            <th>個数</th>
            <th>削除ボタン</th>
        </tr>
        <tr *ngFor="let ringo of Ringo$ | async">
            <td>{{ringo.id}}</td>
            <td>{{ringo.name}}</td>
            <td>{{ringo.counter}}</td>
            <td>
                <input type="submit" value="削除" (click)="deleteRingo(ringo.id)">
            </td>
        </tr>
    </table>
</div>

こちらを実際に動かしたものがこちらになります。

終わりに

今回はEntityStoreを使ってみました。
これは例えば、買い物をするサイトでカートに入れている商品を管理するのに使ったりされています。
Storeの方の記事でも書きましたが、カートの中身を全コンポーネント間で共有できるところが本当に便利です。
良ければ使ってみてください。

スポンサーリンク

Angular開発

Posted by 社畜林檎