【问题标题】:Store API data in subject before subscribing to Observable - Angular 10在订阅 Observable 之前将 API 数据存储在主题中 - Angular 10
【发布时间】:2020-12-10 15:11:43
【问题描述】:

我正在尝试使用 next 方法将从 API 返回的数据存储在行为主题中,我想在订阅 observable 之前执行此操作。

假设我有一个服务,它具有从 API 检索一些数据的功能:

getData(): Observable<Data> {
    return this.http.get(APIURL);
}

现在,在订阅 getData() 之前,我想将 API 返回的内容保存在主题中。我设法用 tap() 运算符实现了这一点,但是通过阅读文档,tap 应该用于副作用,在这种情况下它看起来不像一个。 所以我所做的是这样的:

getData(): Observable<Data> {
        return this.http.get(APIURL)
               .pipe(tap(data => this.subject.next(data));
}

我这样做是为了获得某种缓存,这样我就不必再次调用 API 并在数据更新时对其进行一些操作。例如,假设我使用更新查询向该数据添加了一个元素,现在我可以更新存储在主题中的先前数据,因此一切都是最新的。只有刷新页面,我才会再次调用 API。

我不清楚的是 tap 运算符的使用,这样使用它是否可以,或者对于我正在尝试做的事情有更好的选择吗?

【问题讨论】:

  • 我不完全理解这个问题。但是如果你想在没有订阅的情况下从 API 更新数据,那是不可能的。 Angular HttpClient 是一个独特的 observable,它在第一次通知后立即完成。因此,要保持前端更新,您要么需要一个计时器,以设定的时间间隔连续轮询后端,要么查看Server Sent Events。它们相当容易设置,旨在解决您可能面临的确切情况。

标签: angular rxjs angular-services


【解决方案1】:

这是一个CodeSandbox,它显示了在您不使用状态管理库的情况下管理缓存请求流的一种方法。

demo的精髓如下

interface IArticle {
  title: string;
  content: string;
}

@Injectable({ providedIn: "root" })
export class HttpDemoCache {
  // You need a variable where to store the data
  cachedArticleResponse$: BehaviorSubject<IArticle[]> = new BehaviorSubject([]);
  ...
  loadArticles(someQuery) {
  // You need a method that fetches the data from the BE
    this.httpClient.get(...).subscribe((x) => {
      this.cachedArticleResponse$.next(x);
    });
  }

  updateArticles(newArticle: IArticle) {
  // You need a update method to send the new enttity to the back-end + update your cached version
    this.http.post(...., {newArticle}).pipe(
        switchMap(response => 
        this.cachedArticleResponse$
        .pipe(
              take(1),
              tap(cachedArtilces => this.cachedArticleResponse$
              .next([...cachedArticles, newArticle]))
             )
        )
       ).subscribe()    
      });
  }
}

几乎使用此解决方案,您正在创建自己的状态管理解决方案,其职责是处理所有 cahce/fetch/upload/delete 逻辑。

此解决方案的好处是,与直接在组件中获取数据相比,您可以更好地控制正在发生的事情。

** 旁注:请记住,这是一个非常简短的概念示例,而不是详细的解决方案。

【讨论】:

  • 可以订阅服务吗?我认为这不是一般的好做法,但也许这是唯一的方法?
  • 只要您管理订阅就可以了,您可以将这种方法的上下文中的服务视为一个黑匣子,它负责处理一切和外部世界(您的组件或其他服务)你只是在使用它的 api 而没有摆弄它的内部。
【解决方案2】:

如果我理解正确,您可以检查一下,您在主题中有一些数据

subject = new BehaviorSubject<any>(null);

getData(): Observable<Data> {
   if (subject.getValue()) {
      return of(subject.getValue());
   }
   return this.http.get(APIURL)
        .pipe(tap(data => this.subject.next(data));
}

【讨论】:

  • 我不清楚的是 Tap 操作符的使用,这样使用它是否可以,或者我正在尝试做的事情有更好的选择吗?
猜你喜欢
  • 1970-01-01
  • 2018-03-13
  • 2019-08-24
  • 2021-07-22
  • 2017-04-17
  • 1970-01-01
  • 1970-01-01
  • 2021-03-10
  • 1970-01-01
相关资源
最近更新 更多