NGXS:选择器默认值稍后到达,然后在操作中设置值

时间:2019-06-14 14:37:45

标签: angular observable state-management ngxs

我的状态为默认值。我有一个组件,其ngOnInit中具有选择器和订阅块。奇怪的是,来自后端的数据在此订阅块中被覆盖,因为初始化数据到达的时间晚于我需要的真实数据... 控制台日志语句顺序为:

ngOnInit initData(状态默认值) PatchState searchInit之前(数据来自服务器) initData(数据来自服务器) initData(状态默认值)

我尝试用pipe(first())进行订阅,也曾在setTimeout块中尝试过,不知道发生了什么事...

代码:

状态:

@State<XStateModel>({
    name: 'x',
    defaults: {
        searchInitData: {
            types: [ { id: 1, imageUrl: '', name: 'd'} ],
        }
    }
})

    @Action(FetchXSearchInitData)
    getSearchInitData({ getState, patchState }: StateContext<XStateModel>) {       this.xService.getXSearchInitData().subscribe(initData => {
            console.log('pre PatchState searchInit', initData);
            patchState({
                searchInitData: initData
            });
        });
    }

组件:

  @Select(XState.searchInitData)
  searchInitData$: Observable<XSearchInitData>;

  ngOnInit() {
      console.log('ngOnInit');
      this.store.dispatch(new FetchXSearchInitData());
      this.searchInitData$
      .subscribe(
        (result: XSearchInitData) => {
          if (!result) {
            console.log('NULL init data');
            return;
          }
          console.log('initData', result);
        }
      );

1 个答案:

答案 0 :(得分:0)

首先,您的操作处理程序不正确。我正在解释原因-在NGXS中,当您执行异步工作时,应从表示该异步工作(和完成情况)的Observable方法返回一个Promise@Action。然后,该动作的完成将与异步工作的完成绑定。

正确的方法是:

@Action(FetchXSearchInitData)
getSearchInitData({ getState, patchState }: StateContext<XStateModel>) {
  return this.xService.getXSearchInitData().pipe(
    tap(initData => {
      console.log('pre PatchState searchInit', initData);
      patchState({
        searchInitData: initData
      });
    })
  });
}

在操作“成功”处理之后,将触发dispatch方法返回的可观察对象,因此您可以在操作完成后立即使用以下代码进行订阅:

ngOnInit() {
  console.log('ngOnInit');
  this.store
    .dispatch(new FetchXSearchInitData())
    .pipe(mergeMap(() => this.searchInitData$))
    .subscribe((result: XSearchInitData) => {
      if (!result) {
        console.log('NULL init data');
        return;
      }
      console.log('initData', result);
    });
}