How to use BehaviourSubjects to share data from API call between components in Angular?

前端 未结 6 538
甜味超标
甜味超标 2021-01-28 22:21

I am currently building an Angular application where I make a request to an api, and I map the repsonse to two different arrays. I can use this data in my app.components.t

6条回答
  •  陌清茗
    陌清茗 (楼主)
    2021-01-28 22:54

    This is an answer describing how it can be done using pure RxJS. Another alternative is to use NgRx.

    Firstly, you have set up two subjects. The intention being that all components will subscribe to them and receive the latest data when it is refreshed?

    You should use ReplaySubject instead of BehaviorSubject though, since you don't have any initial state. And since the data comes back as one thing, I would use one subject.

    Firstly, I am going to declare an interface to make it easier to talk about the data types.

    earthquake-data.ts

    export interface EarthquakeData {
      // TODO: create types for these
      geometries: any[]; 
      properties: any[];
    }
    

    In your service, you can separate the retrieval and the notifications by exposing the data via your own methods.

    earthquake.service.ts

      url = 'https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_day.geojson'; 
    
      private _earthquakeData$ = new ReplaySubject(1);
    
      constructor(private readonly httpClient: HttpClient) {}
    
      getEarthquakeData(): Observable {
        // return the subject here
        // subscribers will will notified when the data is refreshed
        return this._earthquakeData$.asObservable(); 
      }
    
      refreshEarthquakeData(): Observable {
        return this.httpClient.get(this.url).pipe(
          tap(response => {
            // notify all subscribers of new data
            this._earthquakeData$.next({
              geometries: response.features.map(x => x.geometry),
              properties: response.features.map(x => x.properties)
            });
          })
        );
      }
    

    So now, all components that want to receive data will subscribe to one method:

    private destroyed$ = new Subject();
    
    ngOnInit()
      this.earthquakeService.getEarthquakeData().pipe(
        // it is now important to unsubscribe from the subject
        takeUntil(this.destroyed$)
      ).subscribe(data => {
        console.log(data); // the latest data
      });
    }
    
    ngOnDestroy() {
      this.destroyed$.next();
      this.destroyed$.complete();
    }
    

    And you can refresh the data wherever you want to:

    refreshData() {
      this.refreshing = true;
      this.earthquakeService.refreshEarthquakeData().subscribe(() => {
        this.refreshing = false;
      });
    }
    

    DEMO: https://stackblitz.com/edit/angular-uv7j33

提交回复
热议问题