在使用 URL 参数加载页面之前等待 ngrx 操作

Waiting for ngrx action before loading page with URL parameter

我正在使用 ngrx 构建一个 ng2 应用程序。启动应用程序时,将调用 Web 服务以获取初始数据,获取此数据后,我将创建一个 INIT_DONE 操作。

我的状态是这样的:

export interface State {
  documents: Document[];
  selectedDocument: Document
}

当我转到页面 /mypage/456 时,其中 456 是一个 url 参数,我需要获取一些已提取的数据,因此我得到了这样的 URL 参数:

ngOnInit() {
  this.paramSubscription = this.route.params
    .select<string>('id')
    .map((id) => new SelectAction(id))
    .subscribe(this.store);
}

SELECT_ACTION在获取的数据中找到元素并设置selectedDocument。问题是 SELECT_ACTION 是在 INIT_DONE 之前创建的,此时 documents 是空的。

如何等待 INIT_DONE 后再加载我的页面?

您可以 select 商店中的文档并订阅它并从那里发出您的操作:

ngOnInit() {
  this.store.select("documents").subscribe(documents => {
    this.paramSubscription = this.route.params
      .select<string>('id')
      .map((id) => new SelectAction(id))
      .subscribe(this.store);
  });  
}

我会使用 combineLatest 运算符,因为它结合了多个源流的最新值。此外,我会使用过滤器仔细检查文档是否已设置(这里我假设它是一个数组)。

ngOnInit() {
  this.subscription = Observable.combineLatest(
      this.store.select("documents")
          .filter(documents => documents.length > 0),
      this.paramSubscription = this.route.params
          .select<string>('id')
  )
  .map((combinedData: [Object[], string]) => combinedData[1])
  .subscribe(this.store);
}

还将订阅分配给一个变量,以便您可以在组件销毁时取消订阅。否则,您的订阅将在组件被销毁后存在,并且您的操作可能仍会发出:

ngOnDestroy() {
    this.subscription.unsubscribe();
}

您需要一个解析器。解析器在完成导航操作之前等待数据可用。

@Injectable()
export class DocumentsResolver implements Resolve {

    constructor(
        private store: Store
    ) {}

    resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Hero> {
        // take id from snapshot
        const id = route.params['id'];
        // start with the document list
        return this.store.select('documents')
          // wait until there is data available
          .filter(documents => documents && documents.length > 0)
          // then produce the selected document
          .mergeMapTo(this.store.select('selectedDocument'));
    }
}

路由配置:

export const DocumentsRoutes: RouterConfig = [
    { path: 'documents/:id', component: DocumentsDetailComponent, resolve: { document: DocumentsResolver } }
];

更多关于路由器解析的信息