当前位置: 首页 > 知识库问答 >
问题:

获取可观察对象当前值的简单方法(从行为主体获取)

杜凯
2023-03-14

这个问题看起来很长,但应该是一个很基础的rxjs问题。如果可以的话请帮忙。

我正在编写一个 Angular 7 应用程序,其中包含如下服务、组件和模板,我想以一种简单的方式访问可观察量的最后一个值。

SoundMeter服务

在服务中,我有一个私有的行为主体,我用它来使用“下一步”发出值。我使用. as观察()将此行为主体暴露给消费者,以防止消费者执行. Next()并发出新值。在服务中,我使用. value访问listeningStastus主题的当前值。

export type SoundMeterStatus    = 'noResults' | 'isRunning' | 'hasResults';

export class SoundMeterService {
    private listeningStatusSubject: BehaviorSubject<SoundMeterStatus> = new BehaviorSubject<SoundMeterStatus>('noResults');
    get listeningStatus()   { return this.listeningStatusSubject.asObservable(); }

    // somewhere in the code I emit a different value
    someFunc() {
        if (this.listeningStatusSubject.value === 'noResults' )
            this.listeningStatusSubject.next('isRunning');
    }
}

声音测量组件

遵循可观察量的最佳实践,在组件中,我使用直接访问服务的可观察量(通过 listeningStatus getter),以便在模板中自动订阅和取消订阅(见下文)。

export class SoundMeterComponent {
    serviceListeningStatus$ = this.sms.listeningStatus;

    constructor(
        private sms: SoundMeterService
    ) {}

    ngOnInit() {
        // I want to check the value of listeningStatus in a simple way without pulling the value out and saving it locally in SoundMeterComponent
    }
}

SoundMeter模板

我使用Angular的异步管道,这样当组件被销毁时,它可以自动订阅和取消订阅可观察对象(以避免这里提到的手动订阅)

<div *ngIf="(serviceListeningStatus | async) === 'noResults' ">
    <span>some text</span>
</div>

我的问题

这种方法非常有效。但是我想在ngOnInit()中以简单的方式检查listeningState的值,而无需将值提取出来并将其本地保存在SoundMeter Component中,也无需公开行为主题listeningStastus本身以使用. value检查其值,如下所述:

1) 从服务中提取值并将其保存在SoundMeterComponent中:

声音测量组件

export class SoundMeterComponent {
        serviceListeningStatus$ = this.sms.listeningStatus;
        private serviceListeningStatus;

        constructor(
            private sms: SoundMeterService
        ) {}

        ngOnInit() {
            // Pulling the value from the service:
            this.sms.listeningStatus.subscribe( status => this.serviceListeningStatus = status ); // I'm trying to avoid this

            if (this.serviceListeningStatus === 'noResults' ) {
                displayNoResultsMessage();
            }
        }
    }

2)公开行为主体本身并使用. value检查其值,如下所示:

SoundMeter服务

export class SoundMeterService {
    private listeningStatus: BehaviorSubject<SoundMeterStatus> = new BehaviorSubject<SoundMeterStatus>('noResults');
    get listeningStatus()   { return this.listeningStatus; }

}

声音测量组件

export class SoundMeterComponent {
    serviceListeningStatus = this.sms.listeningStatus;

    constructor(
        private sms: SoundMeterService
    ) {}

    ngOnInit() {
        if (this.sms.listeningStatus === 'noResults' ) {
            displayNoResultsMessage();
        }
    }
}

SoundMeter模板

<div *ngIf="(serviceListeningStatus.asObservable() | async) === 'noResults' ">
    <span>some text</span>
</div>

请帮我理解哪种方法更好,同时保持干净和简单的代码。我知道有很多关于如何从行为主题中获取值的问题,比如使用rxjs5获取行为主题当前值的简单方法或如何获取RxJS主题或可观察的当前值?,但请注意这是一个不同的问题。谢谢!

共有3个答案

萧晔
2023-03-14

就我所能理解的你的问题而言,我可能首先会质疑行为主题的用法。RxJs虽然很棒,但并不适合每个用例,你的可能就是其中之一。. value的用法是对imo的指示。

SoundMeter Service中使用一个简单的不可观察变量来保持状态可能会解决您的所有问题。

如果您不想这样做,我的建议是尝试如下方法:您的流程中有几个地方您想要检查 listeningStatus 并且您可以选择使用 tap 运算符并在一个地方对所有选项(不仅是“noResults”)执行副作用?

例:

export class SoundMeterComponent {
    serviceListeningStatus$ = this.sms.listeningStatus.pipe(
        tap((status) => {
            if (value === 'noResults') {
                displayNoResultsMessage();
            }
            if (value === 'xxx') {
                doXXXStuff();
            }
        })
    );

    constructor(private sms: SoundMeterService) {}

    ngOnInit() {}
}

然后模板订阅serviceListeningStatus$

<div *ngIf="(serviceListeningStatus$ | async) === 'noResults' ">
    <span>some text</span>
</div>

我认为你的问题是一个很好的例子,对于想要做 RxJs 的应用程序来说,因为它很棒,但由于 Angular 框架中缺乏对响应式方法的完全支持,你不能完全响应式。我正在考虑ngOnInit或用户进行的点击事件。如果你想使用RxJs,看看ngx-template-stream或这个伟大的建议可能会有所帮助。

干杯克里斯

丁理
2023-03-14

恐怕你必须订阅这个.sms.listeningStatus,这就是可观察性的工作原理。如果您想坚持使用真正的异步方法处理数据,就没有解决方法。您唯一能做的就是将订阅移到其他地方(例如,使用异步管道将其移到模板)

东方飞捷
2023-03-14

始终可以将async/await与ngOnInit结合使用

async ngOnInit = () => {
  const currentValue = await this.sms.listeningStatus.pipe(take(1)).toPromise();

  // do stuff with currentValue here
}

(注意:在将热可观察量转换为promise时,请始终使用 take(1) - 否则它们永远不会解析,因为您需要在promise解析之前完成可观察量)。

 类似资料:
  • 我有一个方法返回<code>Single 我可以使用,但这不允许我从中返回列表。 我还尝试了。 编辑 我可以通过以下方式完成这项工作: 请告诉 如果这种方式是正确的 我是反应式编程新手,请解释一下。

  • 如何编写接受并返回的函数? 我得到的错误是类型'Observable'不能分配到类型'Observable'。类型'transaction[]不可分配给类型'transaction'。类型“transaction[]”中缺少属性“id”。 据我所知,可观测管道函数(map、single、find、max等)与数据流有关(即,当可观测器随着时间的推移发出多个项时),当可观测器同时发出单个项(碰巧是一

  • 根据我的理解,是一个可以随时间变化的值(可以订阅,订阅者可以接收更新的结果)。这似乎与的目的完全相同。 何时使用与?使用比使用有好处吗?或者反之亦然?

  • 我有一个servers对象数组,其中在数组中有另一个可观察对象数组,其键是[securityGroups]。 我有另一个securitygroupsArray数组,在这里我使用API来获取所有SecurityGroups。 我需要在securityGroups键中查找服务器阵列中该服务器上安全组的所有名称,并在一个选项中只显示我的其他阵列(securityGroupArray)的ngfor的不同名

  • 我对RxJS很陌生,所以如果这个问题已经得到回答,我提前道歉。 我有一个Angular 2应用程序,在其中一个组件中有一个普通对象。我将UI绑定到这个对象。我想做的是能够捕获对这个对象的所有更改,无论它们来自代码还是来自用户更改其中一个字段。 我正在查看可观察对象,但似乎只有通过Emit方法推送新对象时,订阅者才能接收通知。例如,在属性绑定到输入字段的情况下,这将如何工作? 有更好的方法吗? 这是