Angular中*ngFor生成的子组件订阅服务事件如何仅接收一次?
该行为属于正常现象
RxJS的Subject是多播的,每调用一次subscribe()方法就会生成一个独立的订阅实例。你通过*ngFor生成了多少个B组件,就会执行多少次ngOnInit里的订阅逻辑,自然服务调用next()时每个订阅都会收到通知,10个B组件触发10次是完全符合预期的。
优化方案(按需选择)
方案1:仅对应选中状态的B组件响应事件
如果你的业务逻辑是只有和当前选中step匹配的B组件需要执行回调,可以在订阅前加过滤逻辑,符合条件的B组件才会执行后续操作,从效果上实现仅触发一次需要的业务逻辑:
// B组件代码 import { filter } from 'rxjs'; @Input() step: any; private subscription: Subscription = new Subscription(); constructor(private stepsService: StepsService) { } ngOnInit(): void { this.subscription = this.stepsService.stepSelectedSubObservable$ .pipe( // 只处理和当前组件step匹配的事件 filter(newStepSelected => newStepSelected === this.step) ) .subscribe(newStepSelected => { console.log(newStepSelected); // 只有匹配的B组件会执行回调 }) } // 必须添加销毁时取消订阅逻辑,避免内存泄漏 ngOnDestroy(): void { this.subscription.unsubscribe(); }
方案2:全局仅订阅一次事件
如果你的业务逻辑是不管有多少个B组件,整个应用只需要执行一次事件回调,就不要把订阅逻辑写在循环生成的B组件里,把订阅移到B组件的公共父组件、或者组件A所在的层级即可:
// B组件的父组件代码 private subscription: Subscription = new Subscription(); constructor(private stepsService: StepsService) { } ngOnInit(): void { this.subscription = this.stepsService.stepSelectedSubObservable$.subscribe(newStepSelected => { console.log(newStepSelected); // 只会触发一次 // 如果需要把状态传给对应B组件,可以在这里操作steps数组更新对应项的状态,通过@Input传给B组件即可 }) } ngOnDestroy(): void { this.subscription.unsubscribe(); }
采用该方案时B组件无需再单独订阅服务,直接通过@Input接收父组件传递的状态即可。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

