'Create one subscription for multiple 'observable consumers'
To manager state there is this store service for users. In the store there is a 'select' method which maps to get the users id's:
type User = { userId: number };
@Injectable({ providedIn: "root" })
export class SomeService {
activeUsers$ = new BehaviorSubject<User[]>([]);
selectUserIds = (): Observable<number[]> => {
return this.activeUsers$
.asObservable()
.pipe(map((data) => data.map(({ userId }) => userId)));
};
// ...
}
In the component I am calling that method to see which user is active:
@Component({
selector: "app-root",
template: `
<div>
<h1>See console output</h1>
<ng-container *ngFor="let user of users">
<div [ngClass]="{'active': (activeUserIds$ | async).includes(user.userId)}">
{{ user.userName }}
</div>
</ng-container>
</div>`,
})
export class AppComponent implements OnInit {
activeUserIds$: Observable<number[]>;
users = [
{ userId: 1, userName: "John" },
{ userId: 2, userName: "Fred" },
{ userId: 3, userName: "Alex" }
];
constructor(private someService: SomeService) {}
ngOnInit(): void {
this.activeUserIds$ = this.someService.selectUserIds().pipe(
tap((data) => {
console.log("data: ", data);
}),
);
}
}
But in the console the happens the amount of times it's called in the template (three times):
// console output:
// data: []
// data: []
// data: []
It seems superfluous to have it done three times. But I do want it to react to updates to the state.
My thoughts were that by creating the 'activeUserIds$' in the OnInit I would have 1 observable and use that multiple times. But instead it seems like it's subscribing multiple times.
What would be the way to only have 1 subscription?
Sandbox link: https://codesandbox.io/s/red-bird-n7xips?file=/src/app/app.component.ts
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
