Home > Back-end >  Reactive Loading state management with RxJs
Reactive Loading state management with RxJs

Time:01-23

A classic task when you have some input field and you have to fetch something on values changes. Let's imagine we use Angular Reactive Forms. Example:

orders$ = inputControl.valueChanges.pipe(
   switchMap((value) => {
     return someService.fetch(value);
   })
);

Now we should also somehow manage loading state. I usually use tap:

orders$ = inputControl.valueChanges.pipe(
  tap(() => { loading = true }), // or loading$.next(true) if loading is a subject
  switchMap((value) => {
    return someService.fetch(value);
  }),
  tap(() => { loading = false }), // or loading$.next(false) if loading is a subject
);

However it seems we can somehow avoid assigning values in the tap and use RxJs instead. But I could not find a way to do with it.

For me, the usage of the ideal solution would be

orders$ = <some abstraction here that depends on inputControl.valueChanges and fetching>
loading$ = <some abstraction here that depends on fetching>

CodePudding user response:

You can use the map and shareReplay operators to achieve this. The map operator can be used to return the value from the service call and the shareReplay operator can be used to share the observable and keep the loading state.

orders$ = inputControl.valueChanges.pipe(
  switchMap((value) => {
    return someService.fetch(value).pipe(
      map(data => {
        loading$.next(false);
        return data;
      }),
      startWith({loading: true})
    );
  }),
  shareReplay(1)
);
loading$ = orders$.pipe(map(data => data.loading));

This way you can use the orders$ observable to subscribe to the orders and loading$ observable to subscribe to the loading state. Note : The above example will not work if you return a object from service call, you would need to wrap the object in another object with loading property like {data: {}, loading: true/false}

CodePudding user response:

Take a look at my library ez-state.

https://github.com/adriandavidbrand/ngx-ez/tree/master/projects/ez-state

https://adrianbrand.medium.com/angular-state-management-using-services-built-with-ez-state-9b23f16fb5ae

orderCache = new EzCache<Order[]>();

order$ = this.orderCache.value$;

loading$ = this.orderCache.loading$;

inputControl.valueChanges.subscribe(value => {
  orderCache.load(someService.fetch(value));
});

An EzCache is a glorified behaviour subject that has methods load, save, update and delete and manages state observables like loading$, loaded$, saving$, saved$ etc.

I would personally would have the cache in the service and expose the observables from the service like in that article I wrote.

  • Related