如何正确做一个切换变量?
public toggleLabels$ = new BehaviorSubject<boolean>(true);
public toggleLabels() {
this.toggleLabels$.next(!this.toggleLabels$.getValue());
}
我只是得到相反的值,然后把它推回去。这是一个好方法吗?
通过scan, RxJS有一个内置的状态管理解决方案,可以用于所有状态场景(也包括一些比切换机制更复杂的场景)。
用于封装和管理状态。在初始状态建立后,对来自源的每个值应用累加器(或"reducer函数")——通过种子值(第二个参数)或来自源的第一个值。
const { Subject } = rxjs;
const { scan, startWith } = rxjs.operators;
const toggle$$ = new Subject();
const toggle$ = toggle$$.pipe(
scan((state, curr) => !state, true),
startWith(true)
);
toggle$.subscribe(console.log)
toggle$$.next()
toggle$$.next()
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/7.4.0/rxjs.umd.min.js"></script>
Bryan60提到我的答案并没有像问题逻辑那样完全实现行为。有两个概念上的区别:
- 新订阅者无法获得最后值
- no subscriber表示可观察对象不会计算/发射它的管道对丢失的特性有一个具体的解决方案如果需要:
新用户(replay last value):shareereplay操作符允许你共享一个可观察对象,并重播最后发出的值
分享订阅源和回放指定数量的排放。
没有订户(不会排放管):connectable创建了一个可观察对象,它提供了一个connect
方法。调用这个函数可以让你的可观察对象变得炙手可热并被订阅。然后,它将在没有订阅的情况下发出值。
信息:这两个功能(重放和连接)在大多数时候都是不需要的。在我的上一个项目中,我们看到了过度使用BehaviorSubjects
和multicasting
的启动问题。如果一次只发生一次订阅,并且在发出值之前完成订阅,则不需要重放机制。请始终记住,只有有意识的实现功能,因为它可能会影响启动,运行时性能或给您的应用程序一个意想不到的和不一致的行为。
const { Subject, connectable } = rxjs;
const { scan, startWith, shareReplay } = rxjs.operators;
const toggle$$ = new Subject();
const toggle$ = toggle$$.pipe(
scan((state, curr) => !state, true),
startWith(true),
shareReplay(1)
);
connectable(toggle$).connect()
toggle$.subscribe(v => console.log("first subscribe: ", v))
toggle$$.next()
toggle$$.next()
toggle$.subscribe(v => console.log("second subscribe: ", v))
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/7.4.0/rxjs.umd.min.js"></script>
这对于这么简单的东西很好,但getValue()
不是我习惯使用的东西。在更复杂的情况下,它可能会变得混乱和破裂。
你通常希望在可观察对象中保留状态修改,以确保一切都按照预期的顺序发生。
你可以这样做:
// two subjects, one for saving state, one for signaling toggles
private toggleSource = new Subject();
private toggleLabelsSource = new BehaviorSubject<boolean>(true);
// keep state observables private
toggleLabels$ = this.toggleLabelsSource.asObservable();
constructor() {
// link observables
this.toggleSource.pipe(
scan((toggle, _) => !toggle, true)
).subscribe(this.toggleLabels$);
}
public toggleLabels() {
// call next on toggle signal.
this.toggleSource.next(null);
}
对于这么简单的事情来说,这太复杂了,但是当你处理更复杂的状态转换时,这种模式更有意义。
创建一个包含:
的服务private toggleValue = true;
private toggleLabelsSource = new BehaviorSubject<boolean>(this.toggleValue);
currentToggleLabels = this.toggleLabelsSource.asObservable();
toggleLabels(): void {
this.toggleValue = !this.toggleValue;
this.toggleLabelsSource.next(this.toggleValue);
}
然后你可以听currentToggleLabels
和切换toggleLabels()