ngrx 顺序数据加载

ngrx sequential data loading

我有一个守卫,我想确保在页面可视加载之前预加载数据。我一直在关注 Todd Motto's strategy,预加载只需要一次发送的数据。

问题是,我的场景需要 多个 分派,其中一些依赖于其他分派。

我需要分派以加载对象 A,然后我需要使用对象 A 上的一些数据来加载对象 B

为了这个最小的例子,假设我的状态有 loading(布尔值)和 things[](加载的实体)。当我执行 Get 操作时,loading 被翻转为 true。 loading 在看不见的成功操作中翻转为 false。

canActivate(route: ActivatedRouteSnapshot): Observable<boolean> {
    // fetches the first `thing` with the route's id
    this.store.dispatch(new actions.Get(route.params.id));
    return this.store
        .select(selectState)
        .filter(state => !!!state.loading)
        .do(state => {
            // the first `thing` is loaded
            // now use it to load another `thing`
            this.store.dispatch(new actions.Get(state.things[0].something));
        })
        .take(1)
        .switchMap(() => this.store.select(selectState))
        // in the filter, state.loading is false, even though
        // we just fired a dispatch to say it's loading. 
        // ...because this is checked before the
        // dispatch can flip the boolean
        .filter(state => !!!state.loading)
        .take(1)
        .switchMap(() => Observable.of(true))
        .catch(() => Observable.of(false));
}

虽然第一次 "wait for this to load" 一切正常,但随后的调度不会在下一次 "wait for this to load" 检查之前将我的 loading 状态变量翻转为真。

非常感谢任何帮助,或者更好的模式。

假设我的状态是这样的

{
  user: User;
  userLoaded: boolean;
  userRoles: Role;
  userRolesLoaded: boolean
}

我的目标是在加载用户和用户角色之前不加载路由。

假设我已经为 getUserLoaded 和 getUserRolesLoaded 创建了选择器,只有 return 来自我的状态的布尔值用于它们各自的属性。

这是我加载多个的方法

canActivate(route: ActivatedRouteSnapshot): Observable<boolean> {
  return this.store.select(getUserLoaded).pipe(
      map(loaded => {
        // if my user is loaded this will be true
        if (!loaded) {
          this.store.dispatch(new fromStore.LoadUser());
        }
      }),
      filter(loaded) => loaded),
      take(1),
      withLatestFrom(this.store.select(fromStore.getUserRolesLoaded)),
      map(([nullData, loaded]) => {
        if(!loaded) {
          this.store.dispatch(new fromStore.LoadUserRoles()
        }
      }),
      withLatestFrom(this.store.select(fromStore.getUserRolesLoaded)),
      filter(([data, loaded]) => loaded),
      take(1)
    );
}

所以在这里我首先得到状态片段,它是我的 userLoaded 布尔值。如果我的用户未加载,那么我将发送加载用户的操作。然后我对其进行过滤,使其在 true 之前不会 return 并取消订阅。接下来我得到状态片,它应该有 getUserRolesLoaded 并且我检查它们是否被加载,如果没有我发送,添加一个过滤器等待 true 并取 1.

我正在使用 rxjs 5.5 中引入的管道方法,但根据您的需要转换它应该不会太难。对我来说,我觉得关键是了解我选择的状态切片以确保我正在检查正确加载的数据。

也许试试这个快速技巧

.take(1)
    .switchMap(() => this.store.select(selectState).pluck('loading').distingUntilChanged()
)

只有当它从 false 切换到 true 时才会触发,反之亦然。或者使用中间状态,beforeload->loading->loaded

我一直在努力了解 为什么 代码的行为如此,以防其他人想知道:

@ngrx/store State class 使用 rxjs observeOn 运算符和 queueScheduler 创建了一个 Observable actionsOnQueue。正是这些排队的动作被馈送到减速器以产生新状态。然后新状态发出并触发任何选择器。

第一个分派在解析器的上下文中执行并同步运行。下一行创建一个 Observable,它从 store 中选择并立即看到 Get 操作的效果。因此过滤器会忽略 loading=true 的初始状态,管道等待加载完成。

稍后调度和减少 Success 操作(设置 loading=false)时,商店将发出并通过过滤器。然后将执行第二个调度。 queueScheduler 意味着此调度不会同步执行,因为我们正在执行 'inside' Success 操作的调度。

然后 switchMap 将再次订阅存储 ,然后在第二个 Get 操作被缩减为状态 并看到 loading=false 的陈旧状态。