Angular中Observable更新布尔值与数组时视图表现不一致的问题求助
Angular中Observable更新布尔值与数组时视图表现不一致的问题求助
嗨,我明白你现在的困惑——明明在服务里同时更新了数组和布尔值,视图里数组能实时刷新,布尔值却纹丝不动,只有重新订阅才会更新。咱们先把你的代码摆出来,再一步步拆解原因:
服务代码(test.service.ts)
import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; @Injectable() export class TestService { private myNumbers: number[] = [Math.random()] myBoolean: boolean = false updateData() { this.myNumbers.push(Math.random()) this.myBoolean = !this.myBoolean } getNumbers(): Observable<number[]> { return Observable.of(this.myNumbers); } getBoolean(): Observable<boolean> { this.myBoolean = !this.myBoolean return Observable.of(this.myBoolean); } }
组件代码(app.component.ts)
import { Component, OnInit } from '@angular/core'; import { TestService } from './test.service'; @Component({ selector: 'my-app', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit { name = 'Angular 5'; constructor(private dataService: TestService) {} myNumbers: number[] = []; myBoolean: boolean | undefined = undefined; ngOnInit() { this.dataService.getNumbers().subscribe({ next: (value) => this.myNumbers = value }) this.dataService.getBoolean().subscribe({ next: (val: boolean) => this.myBoolean = val }) } subscribe_bool() { this.dataService.getBoolean().subscribe({ next: (val) => this.myBoolean = val }) } update_data() { this.dataService.updateData(); } }
模板代码(app.component.html)
<br> <button (click)="update_data()">Update data</button> Push data in array and change boolean in service (does not update the boolean in the view ) <br> <br> <button (click)="subscribe_bool()">new subscribe boolean</button> new subscribe (change the view) <hr> <hr> <div *ngFor="let n of myNumbers;let i=index"> item {{i}}: {{n}} </div> boolean data: {{myBoolean}}
问题原因拆解
这核心是引用类型和值类型的差异,再加上Observable.of()的特性导致的:
- 对于数组(引用类型):
Observable.of(this.myNumbers)返回的是当前数组的引用。当你调用updateData()里的push方法时,你是在修改这个引用指向的数组本身的内容,组件里的myNumbers变量和服务里的myNumbers指向的是同一个数组对象。Angular的变更检测能检测到数组内容的变化,所以视图会自动更新。 - 对于布尔值(值类型):
Observable.of(this.myBoolean)返回的是当前布尔值的快照——也就是调用getBoolean()那一刻的布尔值。当你后续在updateData()里修改myBoolean时,这个Observable已经完成了发射,不会再给组件的订阅者发送新值。所以组件里的myBoolean还是停留在第一次订阅时拿到的那个值,视图自然不会更新。而你点击“new subscribe boolean”按钮时,重新调用了getBoolean(),这时候会创建一个新的Observable,发射最新的布尔值快照,所以视图才会更新。
解决方案:用BehaviorSubject替代Observable.of()
要让布尔值的变化能实时通知到组件,你需要用有状态的Observable,比如BehaviorSubject——它会保存当前的最新值,并且在新订阅者订阅时自动发送这个值,同时每次调用next()时都会把新值推送给所有订阅者。修改后的服务代码如下:
import { Injectable } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; @Injectable() export class TestService { private myNumbers: number[] = [Math.random()] // 用BehaviorSubject初始化布尔值,初始值设为false private myBooleanSubject = new BehaviorSubject<boolean>(false); // 对外暴露只读的Observable,避免外部直接调用next() myBoolean$ = this.myBooleanSubject.asObservable(); updateData() { this.myNumbers.push(Math.random()) // 调用next()推送新的布尔值 this.myBooleanSubject.next(!this.myBooleanSubject.value); } getNumbers() { // 这里如果要让数组变化也能稳定实时通知,推荐统一用BehaviorSubject return new BehaviorSubject(this.myNumbers).asObservable(); } }
然后修改组件的订阅逻辑:
ngOnInit() { this.dataService.getNumbers().subscribe({ next: (value) => this.myNumbers = value }) // 订阅服务里的myBoolean$ this.dataService.myBoolean$.subscribe({ next: (val: boolean) => this.myBoolean = val }) }
这样一来,每次调用updateData()时,布尔值的变化会通过BehaviorSubject.next()推送给所有订阅者,视图就能实时更新啦!
备注:内容来源于stack exchange,提问作者vinx
相关产品推荐
相关产品推荐

