javascript - 在 Angular 2 中进行 http 调用后返回热/共享可观察值的最佳方法是什么

标签 javascript angular rxjs

这是我的第一篇文章,所以我希望我做得正确。

我正在尝试找出使用解析器并在子路由组件与其父路由组件之间共享状态的最佳方法。

我有一个 Angular 2 应用程序,它有一个组件/路由结构,其中包含一个父路由和两个子路由,如下面的代码示例所示:

路线:

export const personRoutes: Routes =  [
{ path: 'home/:id', component: MyDetailsComponent,
  resolve: {
    person: PersonResolver
  },
  children: [
    { path: '', component: MyDetailsOverviewComponent, pathMatch: 'full' },
    { path: 'update', component: UpdateMyDetailsComponent }
  ]
}];

我在父路由上使用解析器来在加载其 View 和后续子路由 View 之前获取一些数据。数据是从进行 api 调用的服务中获取的。

解析器:

export class PersonResolver implements Resolve<any> {
    constructor(private personService: PersonService) { }

    resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Person> {
       let id: string = route.params['id'];
       return this.personService.getPerson(id);
    }
}

服务:

getPerson(id: string): Observable<Person> {
    let params = new URLSearchParams();
    params.set('id', id);
    return this.http.get(this.config.apiEndpoint + '/People/', { search: params })
        .map((r: Response) => {
            let person = r.json() as Person;
            this.extractPersonData(person);
            return this.currentPerson.asObservable();
        })
        .catch(error => {
            console.log(error);
            return Observable.throw(error);
        }).share();
}

该服务映射从 http 调用返回的数据,并使用它为 ReplaySubject 提供第一个值,然后由父组件和子路由组件订阅该值。

这里是使用从 http/api 调用返回的数据调用的 extractPersonData 函数/this.currentPerson 是组件将订阅的缓冲区为 1 的 ReplaySubject。

extractPersonData(person: Person): void {
    PersonService.cleanPersonData(person);
    this.currentPerson.next(person);
}

我想在所有三个组件之间共享 person 对象的状态,并且不能使用 @Input/@Output 变量,因为子路由是动态加载到父级路由器导出中的。

下面的代码显示了解析后父组件和子组件之一订阅 ReplaySubject:

父组件:

export class MyDetailsComponent implements OnInit {

  private person: Person;
  private subscription: Subscription;

  constructor(private route: ActivatedRoute, private personService: PersonService, private modalService: NgbModal) {
    this.route.data.subscribe((obs: Observable<Person>) => {
      console.log(obs);
      this.subscription = obs['person'].subscribe(person => {
      this.person = person;
    })
  },
  error => {
    console.log('Home Component - Init person error: ' + error);
  });
}

子组件:

export class MyDetailsOverviewComponent implements OnInit {

  private person: Person;
  private subscription: Subscription;
  isReady: boolean = false;

  constructor(private route: ActivatedRoute) {
    this.route.parent.data.subscribe((obs: Observable<Person>) => {
      this.person = obs['person'];
      this.subscription = obs['person'].subscribe(person => {
        this.person = person;
      });
    });
  }

我的想法是在服务中拥有一个每个组件都可以调用的更新方法。 update 方法应该在内部调用 this.currentPerson.next(newPerson) ,然后兄弟子组件和父组件应该被通知彼此引起的更改。

我的问题是,这是否是在父路由和子路由之间共享状态的糟糕方法?有没有其他方法可以做到这一点。目前,我认为我正在泄漏父组件和子组件中的订阅者,并且在另一个组件中进行订阅调用感觉不对,如下所示:

this.route.data.subscribe((obs: Observable<Person>) => {
  console.log(obs);
  this.subscription = obs['person'].subscribe(person => {
  this.person = person;
})

谢谢。

最佳答案

是的,订阅里面的订阅很菜鸟。使用平面 map 代替。

一些需要消化的代码

  public tagsTextStream = this.tagsTextSubject.asObservable().flatMap((q: string) => {
    // noinspection UnnecessaryLocalVariableJS
    let restStream = this.restQueryService.getTagsList(q)
      .map((tags: any) => {
        // filter out any tags that already exist on the document
        let allTags = _.map(tags, 'name');
        let documentTags = _.map(this.tags, 'name');
        return _.pull(allTags, ...documentTags);
      })
      .catch((err: any) => {
        return Observable.throw(err);
      });
    return restStream;
  }).publish().refCount();

关于javascript - 在 Angular 2 中进行 http 调用后返回热/共享可观察值的最佳方法是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40808822/

相关文章:

JavaScript 在调用相同函数之前清除超时

angular - 如何捕获 angular(ionic) 中的 http 错误?

angular - Angular 2路由器中间的通配符选择器

angular - 如何创建新部分,在angular2中点击新按钮

Angular:串联和并联组合 Observables

error-handling - 捕获并替换Rx可观察到的流/序列

javascript - Dust js 如何在循环中至少检查一次条件是否为真

javascript - 如果从特定 URL 定向到该页面,则取消脚本

javascript - d3 Javascript - 绘制多边形

Angular 5 - 将服务限制为模块