Angular 2+-数据加载:最佳实践

时间:2018-06-27 17:16:30

标签: angular angular-router angular-resolver

我想知道最好的方法是在Angular 5中加载数据。当然,我们要保持组件哑巴;)目前,我正在使用解析器,而Angular在特定的路由中调用该解析器。基本上,数据是在组件初始化之前加载的,因此我可以向用户展示加载程序的动画。

例如

AResolver.resolver.ts

shutdownNow()

M.module.ts

@Injectable()
export class AResolver implements Resolve<any> {
    constructor(private readonly aService: AService) {}

    resolve(route: ActivatedRouteSnapshot) {
        return this.aService.find(route.paramMap.get('id'));
    }
}

AComponent.component.ts

export const MRoutes: Routes = [
    {
        path: 'route-x',
        component: AComponent,
        resolve: AResolver
    }
];

到目前为止,还不错,但是:

  1. 如果我的解析器具有依赖性,该怎么办?因此,要解析B,我们需要A的ID?我应该使用解析器包装器吗?因此,我做了类似的事情:

示例

@Component({
    selector: 'a-super-fancy-name',
})
export class AComponent {

    constructor(private readonly route: ActivatedRoute) {}

}

我猜这是最好的方法,因为我们仍然有2个可重用的独立解析器。通常,为需要数据的所有组件或仅为依赖于其他解析器的解析器创建解析器包装是一种好习惯,还是我根本不应该使用解析器包装?

  1. 解析器中的其他方法(例如@Injectable() export class ABResolver implements Resolve<any> { constructor(private readonly aService: AService, private readonly bService: BService) {} resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { return this.aService.resolve(route, state).map((result) => this.bService.resolveWithId(result.Id)); } } )如何?

  2. resolveWithId route.paramMap中的
  3. 用于获取ID。传递ID会更好,因为它看起来紧密耦合吗?

  4. 有哪些替代方案?

  5. 我使用的方法有哪些缺点?

2 个答案:

答案 0 :(得分:0)

解析器在纸面上是好的,但是只有当您可以轻松地从当前路径获取所有参数时,不幸的是这种情况很少见,有时您将不得不访问父路径,有时您不想在路径中存储所有信息参数,有时您不想阻止导航,路由器参数也不是很灵活的功能,它很容易使重构复杂化(您不能简单地更改父路由参数而不影响子解析器,并且编译器无法检查错误)。

没有任何预定义/推荐的方式来加载数据。根据应用程序的规模,您可以根据需要简单地在每个组件中加载数据,或者强加某些规则或通用接口/抽象类,或通过rxjs等使用缓存共享服务。 基本上,您只能在自定义架构和类似Redux的ngrx方法之间进行选择。 ngrx显然施加了一些限制和限制,并提供了结构和总体方向。

答案 1 :(得分:0)

相反,您可以使用InjectionToken

export const DI_ROUTE_ID = new InjectionToken<Observable<string>>('Route id$');

export function factoryRouteId(routeService: WhateverRouteParamObserver): Observable<string> {
  return routeService.params$.pipe(map((params) => params?.id ?? null));
}

export const DI_ROUTE_ID_PROVIDER: Provider = {
  provide: DI_ROUTE_ID,
  deps: [WhateverRouteParamObserver],
  useFactory: factoryRouteId,
};

在某些模块(可能直接在app.module中)中提供它,即:

@NgModule({
  providers: [
    ...
    DI_ROUTE_ID_PROVIDER,
  ],
})

然后在需要的地方注入。

export class DetailComponent {
  constructor(
    @Inject(DI_ROUTE_ID) private readonly id$: Observable<string>,
  ) {}
...

您还可以创建另一个依赖于此ID令牌和http服务的DI令牌,并直接提供Observable<WhateverDetailData>(并且您可以直接在令牌中共享重放)。

export const DI_ROUTE_DETAILS = new InjectionToken<Observable<DetailsData>>('Route details$');

export function factoryRouteDetails(id$: Observable<string>, httpDataService: HttpDataService): Observable<DetailsData> {
  return id$.pipe(
    switchMap((id) => httpDataService.getData$(id).pipe(
      catchError(() => of(null))
    ),
    shareReplay({refCount: true, bufferSize: 1}),
  );
}

export const DI_ROUTE_DETAILS_PROVIDER: Provider = {
  provide: DI_ROUTE_DETAILS,
  deps: [DI_ROUTE_ID, HttpDataService],
  useFactory: factoryRouteDetails,
};