【问题标题】:How do I force a refresh on an Observable service in Angular2?如何强制刷新 Angular2 中的 Observable 服务?
【发布时间】:2016-10-25 21:01:31
【问题描述】:

ngOnInit 中,我的组件获取用户列表,如下所示:

this.userService.getUsers().subscribe(users => {
    this.users = users;
});

userService.getUsers() 的实现如下所示:

getUsers() : Observable<UserModel[]> {
    return this.http.get('http://localhost:3000/api/user')
                    .map((res: Response) => <UserModel[]>res.json().result)
                    .catch((error: any) => Observable.throw(error.json().error || 'Internal error occurred'));
}

现在,在另一个组件中,我有一个可以创建新用户的表单。问题是当我使用第二个组件创建用户时,第一个组件不知道它应该向后端发出新的 GET 请求以刷新其用户视图。我怎样才能告诉它这样做?

我知道理想情况下我想跳过那个额外的 HTTP GET 请求,并简单地附加客户端在进行 POST 以插入数据时已经拥有的数据,但我想知道它是如何完成的在由于某种原因无法做到的情况下。

【问题讨论】:

    标签: angular rxjs


    【解决方案1】:

    为了让 observable 在初始 Http observable 完成后能够提供值,它可以由 RxJS 主题提供。由于缓存行为是可取的,ReplaySubject 适合这种情况。

    应该是这样的

    class UserService {
      private usersSubject: Subject;
      private usersRequest: Observable;
      private usersSubscription: Subscription;
    
      constructor(private http: Http) {
        this.usersSubject = new ReplaySubject(1);
      }
    
      getUsers(refresh: boolean = false) {
        if (refresh || !this.usersRequest) {
          this.usersRequest = this.http.get(...).map(res => res.json().result);
    
          this.usersRequest.subscribe(
            result => this.usersSubject.next(result),
            err => this.usersSubject.error(err)
          );
        }
    
        return this.usersSubject.asObservable();
      }
      onDestroy() {
        this.usersSubscription.unsubscribe();
      }
    }
    

    由于主题已经存在,无需从服务器更新列表即可推送新用户:

    this.getUsers().take(1).subscribe(users => 
      this.usersSubject.next([...users, newUser])
    )
    

    【讨论】:

    • 这里有很多很棒的答案。我采用了您建议的方法,效果很好。
    • 如何使用此方法退订?
    • 与任何其他 observable 一样;使用this.usersSubject.unsubscribe() 或从observable 保存订阅并在服务ngOnDestroy 上调用unsubscribe。由于 Http 会产生完整的 observables,因此可能不需要取消订阅,尽管这样做会更好。
    • 通过寻找解决方案我得到了这个错误Generic type 'Subject&lt;T&gt;' requires 1 type argument(s).
    • @xaunlopez 我不会说这是一种不好的做法,但退订是一种很好的做法。请参阅我上面关于订阅的评论。您建议的代码看起来不错,但根据我对您建议使用它的理解,意图不同。由于消费者可以重新订阅 observable,服务将再次执行不必要的请求,同时仍通过 usersSubject 返回缓存数据。如果您知道在未提供 refresh 时如何在不发出请求的情况下进行缓存,请考虑使用派生代码发布答案。
    【解决方案2】:

    到目前为止,我处理此问题的方法是使用中介。 this.userService.getUsers() 返回一个 Rx.BehviorSubject,它在返回 http observable 时初始化。

    类似的东西:

    getUsers() : BehaviorSubject<UserModel[]> {
      return this.behaviorSubject;
    }
    updateUsers() {
        this.http.get('http://localhost:3000/api/user')
                        .map((res: Response) => <UserModel[]>res.json().result)
                        .catch((error: any) => Observable.throw(error.json().error || 'Internal error occurred'))
                        .subscribe((value) => {
                          this.behaviorSubject.next(value)});
    }
    

    【讨论】:

    • 这在技术上是最简单的“redux”商店:-) 相同的概念。
    • 这可能有点超出了这个问题的范围,但是...... behaviorSubject 是否适用于异步管道?
    • @bvdb 哇,死评论复活了。行为主体应该使用异步管道。自从我在 Angular 中工作以来已经有很长一段时间了,但是基于这个关于 Rx Subject 问题的评论链,行为主题在异步管道中工作得很好。 github.com/angular/angular/issues/12129
    猜你喜欢
    • 2017-09-28
    • 1970-01-01
    • 1970-01-01
    • 2011-05-07
    • 2013-12-05
    • 2017-06-24
    • 2018-01-27
    • 2016-08-01
    • 1970-01-01
    相关资源
    最近更新 更多