'Subscriptions are not getting updated with latest value when pending api calls are finished after component is destroyed

parent component.html

<child-component *ngIf="showChild"></child-component>

child component.ts

@UntilDestroy()
@Component({
    selector: 'child-component',
    templateUrl: './child-component.html',
    styleUrls: ['./child-component.scss']
})
export class MyChildComponent implements OnInit, OnDestroy {
  myStoreData
  constructor(store) {
    this.store
    .select(myData)
    .pipe(untilDestroyed(this))
    .subscribe((myStoreData) => (this.myStoreData= myStoreData));
  }

 async makeApiCall() {
   try {
     let x = await fetch(api) // <-- Lets say this took 5 seconds, and the component was destroyed when this was ongoing
     this.store.dispatch(myActionThatChangesMyStoreData({ data: x ))
     if (this.myStoreData.someCondition) {  // <-- after api is finished and this executed (and the component is destroyed), myStoreData still has old stale data and is not changed from the "myActionThatChangesMyStoreData" action.
       this.store.dispatch(myOtherAction({ data: "abc" ))
     }
    }
    catch (error) {
    }
 }
}

I normally unsubscribe from all subscriptions when component is destroyed. I use until-destroy library for this purpose.

While the makeApiCall is executing in the child component and the showChild variable in parent is made false, the child component is destroyed and thus all subscriptions from store are destroyed because of untilDestroy. But the component is still in memory as there is a pending xhr request and when the request is fulfilled, the further actions work with outdated store data (since all subscriptions are unsubscribed) and the whole function logic goes wrong.

So in short, When a component is destroyed, how can I make sure I get the latest store data after the pending xhr request completes? I can think of some hacks like after xhr request is completed, check if the component is destroyed (via isDestroyed variable) and if that variable is true subscribe again to get the latest value from store and then immediately unsubscribe. But is there a better way to handle these scenarios

Thank you!



Solution 1:[1]

Move the whole ASYNC functionality to the effect. Create a new action, which will be dispatched from the component and the whole logic of API call will happen in the effect.

That way, even if the component is destroyed, everything is updated as it should be.

//change
async makeApiCall() {
...
}
// to
fetchData() {
  this.store.dispatch(myFetchDatAction());
}

//and have the effect ready
//data.effects.ts

fetchData$ = createEffect(() =>
  ofType(myFetchDatAction),
  switchMap(() => {
    // do the async stuff here
  })
)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 mat.hudak