Каков наилучший способ реагировать на изменения состояния ngxs в вашем компоненте для событий загрузки или ошибок?

У меня есть PostListComponent, который перебирает все сообщения, полученные с сервера и отображает отдельные PostItemComponent. Я использую NGXS для управления состоянием. Когда я инициирую запросы fetchPosts, я изменяю свойство загрузки состояния: true. Когда запрос завершается успешно, я изменяю его обратно на false. Если запрос не выполняется, я обновляю объект ошибки в состоянии и обновляю свойство сообщения объекта ошибки и свойство исключения.

Вот что у меня так далеко

`
export class PostListComponent implements OnInit {    
  private posts$: Observable<any> = this.store.select(state => state.posts);
  private isLoading: boolean = false;
  private error: object = {};

  constructor(
    public postsFacade: PostsFacadeService,
    public moviesFacade: MoviesFacadeService,
    private store: Store) {    
  }

  ngOnInit() {
    this.posts$.subscribe(
      (state) => this.onLoadingEvent(state)
      );

    this.posts$.subscribe(
      (error) => this.onErrorEvent(error)
    )
    // this.posts$.pipe(
    //   mergeMap(() => {
    //     // perform the subscription here and listen for state changes
    //   })
    // )

  }

  onErrorEvent(error)
  {
    this.error = error.error;
  }

  onLoadingEvent(state)
  {
    this.isLoading = state.loading;  
  }
`

Структура моего магазина

`
@State<PostStateModel>({
    name: 'posts',
    defaults: {
        posts: [],
        loading: false,
        error: {
          message: "",
          error: ""                   
        },
    }
})
`

Я чувствую, что есть лучший способ подписаться на изменения состояния в магазине с использованием, возможно, оператора rxjs mergeMap. Я не уверен, возможно ли это и эффективен ли нынешний подход. Как еще я могу подписаться и реагировать на изменения магазина внутри моего компонента?

2 ответа

Итак, несколько вещей:

  1. Вам нужно определить некоторые действия для вашего класса состояний - например, LoadPosts.
  2. Вы должны отправить это действие (скажем, в вашем ngOnInit) или куда-то до загрузки компонента. Действие должно вызывать сервисы, которые фактически извлекают данные, тем самым удаляя эту зависимость из вашего компонента.
  3. Если служба использует Observables или Promises, вы должны обработать, когда они наконец вернутся, обновив ваше состояние в этот момент.
  4. Вы можете создать свою наблюдаемую с помощью @Select. Обратите внимание, что таким образом это напечатано.

    @Select (PostState) postState $: Observable;

  5. Вы можете использовать асинхронный канал в своем компоненте, и вам может не потребоваться подписка на postState $ непосредственно в вашем коде (например, для использования * ngFor для итерации по сообщениям).

  6. Поскольку ваше состояние включает в себя сообщения, флаг загрузки и ошибку, подписка на состояние в целом приведет к запуску вашей функции подписки или асинхронного канала независимо от того, какие из этих изменений. Если вы создаете методы селектора с помощью @Selector() в своем классе состояний, вы можете подписаться на них для большей детализации, например, чтобы реагировать только на флаг загрузки.

Ответ кажется довольно тяжелым и включает в себя настройку перехватчика для вашего приложения. Тогда к нему будут всплывать ошибки.

ngxs.io/advanced/ошибки

Если вы не готовы к созданию этой установки полного цикла, вы можете сделать облегченную версию, сообщив статус ответа «срез».resStatus.

      export interface IReqStatus {
  loading?: boolean;
  error?: any;
  success?: boolean;
  action?: string; <-- optionally send along the action this belongs to
}

Пример действия, выполняющего запрос к конечной точке API

      @Action(UpdateSomething)
updateSomething(ctx: StateContext<SomeStateModel>, { payload }: any): any {

   // 1. update the resStatus to show "busy"
  ctx.dispatch(new UpdateResStatus({ loading: true, action: 'updateSomething' }));

  return this.apiService.patch('/something/endpoint', payload).pipe(
    tap((res) => {
      // 2. update resStatus to show success
      ctx.dispatch(new UpdateResStatus(res));
    }),

    // 3. update the resStatus with errors
    catchError((err: any) => {
      return ctx.dispatch(new UpdateResStatus(err));
    })
  );
}

Используйте действие для управления статусом ответа

      @Action(UpdateResStatus)
updateResStatus(ctx: StateContext<SomeStateModel>, { payload }: any): Observable<any> {
  let status = {
    loading: false,
    success: payload?.status == 'success',
    error: payload?.status == 'success',
    ...(payload?.action && { action: payload?.action }),
  };
  ctx.setState(patch<SomeStateModel>({ reqStatus: status }));
  return of(payload);
}

В моем случае сервер отвечает свойством статуса успеха. Но если запрос полностью нарушен, catchError должен обновитьreqStatus.

Вы можете просматривать статусы ваших запросов с помощьюstate.reqStatusв любом месте. И, надеюсь, вы даже сможете сохранитьasync pipeв такте, как:

      <button [loading]="$any(reqStatus$ | async).loading" ...>
Другие вопросы по тегам