Search code examples
angularngrx

Angular: How to deal with shared data between components


For example, I have an account information that contains balance field (I fetch it from the server):

export class Account {
  constructor(
    // ...
    public balance: number  
  ) {
  }
}

I also have two components in which I need this field. Actually, the question is: how can I retrieve this account in my components?
I have a few assumptions:

#1
Fetch an account information in each component:

// First Component
this.accountService.get().subscribe(...);
// Second Component
this.accountService.get().subscribe(...);

This is the worst solution since I send two requests to the server.

#2
Fetch an account information in the AppComponent and then pass it to the children as inputs.
This is closer to the truth, but how can I pass this data to the router outlet?

<!-- Is this even possible? -->
<router-outlet [account]="account"></router-outlet>

#3
Use NgRx. Perhaps the best solution. The problem is that I don't need NgRx for other manipulations (In my case, it creates more problems than it solves), so I don't want to download such a big library and store it in my bundle.


So, should I consider using NgRx or you can advise me better approach for this problem?

P.S. I also have WebSockets that send me a new balance. I have to manage this as well. This looks like this:

this.socket.fromEvent('new_balance').subscribe(...);

Solution

  • Please don't go for NgRx just for this. It's one of the most common mistakes people do. There are 'Angular' ways on how to deal with it.

    #1

    If you have a child - parent connection between your components. You can communicate in between them using @Input / @Output decorators.

    export class AccountChild {
      @Input() balance: number;
    }
    

    And then in parent component (component where you are calling AccountChild) you pass the balance like this:

    <acconut-child [balance]="balance"></account-child>
    

    #2

    Another option would be to create a Subject out of your API response, and then you can subscribe to it from any other component.

    export class AccountService {
      public accounts: Subject<any> = new Subject();
    
      constructor(
        private http: HttpClient
      ) { }
    
      fetchAccounts() {
        return this.http.get(...).pipe(
          map((result) => {
             this.accounts.next(result);
          }));
      }
    
    }
    

    In order to call the API and load the subject with data you do this:

    this.accountService.fetchAccounts().subscribe();
    

    And now subscribe to that subject from component where you need that info.

    this.accountService.accounts.subscribe((res) => console.log(res));
    

    If you go for a way with subject and subscription it is important to unsubscribe manually from it when you are no longer using that component.

    ngOnDestroy() {
      this.accountService.accounts.unsubscribe();
    }