[NGXS] Action Handler, Action Life Cycle


Action Life Cycle


NGXSのすべての動作は4つの状態で存在する.
DISPATCHED, ERRORED, CANCLEED, SUCCESSFUL
アクションは、ActionContextという名前のオブジェクトを内部ストリームに解放します.
このオブジェクトは、次の構造で構成されています.
{
  action: GetNovelsInstance,
  status: 'DISPATCHED'
}
ActionContextは、上記のアクションが成功すると、次のオブジェクトを解放します.
{
  action: GetNovelsInstance,
  status: 'SUCCESSFUL'
}
ある動作がエラーを貫通した場合、
@Action(GetNovels)
getNovels() {
  throw new Error('This is just a simple error!');
}
ActionContextは、次の形式で作成されます.
{
  action: GetNovelsInstance,
  status: 'ERRORED'
}
非同期の場合、ある動作が終了する前に新しい動作が発生すると、ActionContext CANCELEED状態になります.
また、cacelUnCompletedプロパティを与えると、switch Mapのように動作します.
export class NovelsState {
  constructor(private novelsService: NovelsService) {}

  @Action(GetNovels, { cancelUncompleted: true })
  getNovels(ctx: StateContext<Novel[]>) {
    return this.novelsService.getNovels().pipe(
      tap(novels => {
        ctx.setState(novels);
      })
    );
  }
}

非同期アクション


はい.
export interface BooksStateModel {
  novels: Book[];
  detectives: Book[];
}

export class GetNovels {
  static type = '[Books] Get novels';
}

export class GetDetectives {
  static type = '[Books] Get detectives';
}

@State<BooksStateModel>({
  name: 'books',
  defaults: {
    novels: [],
    detectives: []
  }
})
@Injectable()
export class BooksState {
  constructor(private booksService: BooksService) {}

  @Action(GetNovels)
  getNovels(ctx: StateContext<BooksStateModel>) {
    return this.booksService.getNovels().pipe(
      tap(novels => {
        ctx.patchState({ novels });
      })
    );
  }

  @Action(GetDetectives)
  getDetectives(ctx: StateContext<BooksStateModel>) {
    return this.booksService.getDetectives().pipe(
      tap(detectives => {
        ctx.patchState({ detectives });
      })
    );
  }
}
store
  .dispatch(new GetNovels())
  .subscribe(() => {
    ...
  });

store
  .dispatch(new GetDetectives())
  .subscribe(() => {
    ...
  });
GetNovels()→GetDetectionves()の順に完了したいと考えています.
しかしHTTP応答はいつ応答するか分からないので、後で小説を設定するかもしれません.
代替案として、
store
  .dispatch([
    new GetNovels(),
    new GetDetectives()
  ])
  .subscribe(() => {
    ...
  });
配列に従ってスケジューリングを行うと、2つの動作が完了したときにのみsubscribeが行われる.

Error life cycle


上記の例では、エラーは、かなりのonErrorコールバックとして受信することができる.
store
  .dispatch([
    new GetNovelById(id), // action handler throws `new Error(...)`
    new GetDetectiveById(id)
  ])
  .subscribe(
    () => {
      // they will never see me
    },
    error => {
      console.log(error); // `Error` that was thrown by the `getNovelById` handler
    }
  );

Asynchronous Actions continued - "Fire and forget" vs "Fire and wait"


NGXSが@Actionを返すと、observiceを購読し、アクションの完了をバインドします.
非同期が完了するまで待たないなら、車に戻らないでください.
また、観察可能な場合はsubscribeまたはtoPromise()を使用してください.
もう1つの「fire and forget」メソッドの使用先は、新しい動作をスケジューリングするときです.
Child Actionを待つ必要がない場合、次のように割り当てられます.
export class BooksState {
  constructor(private booksService: BooksService) {}

  @Action(GetNovels)
  getNovels(ctx: StateContext<BooksStateModel>) {
    return this.booksService.getNovels().pipe(
      tap(novels => {
        ctx.patchState({ novels });
        ctx.dispatch(new GetDetectives());
      })
    );
  }

  @Action(GetDetectives)
  getDetectives(ctx: StateContext<BooksStateModel>) {
    return this.booksService.getDetectives().pipe(
      tap(detectives => {
        ctx.patchState({ detectives });
      })
    );
  }
}
逆に待ちたい場合は、mergeMap(switch Map、concatMapなど)を使用して戻ります.
@Action(GetNovels)
getNovels(ctx: StateContext<BooksStateModel>) {
  return this.booksService.getNovels().pipe(
    tap(novels => {
      ctx.patchState({ novels });
    }),
    mergeMap(() => ctx.dispatch(new GetDetectives()))
  );
}