如何切换 rxjs 变量?
How to toggle rxjs variable?
做一个切换变量有多正确?
public toggleLabels$ = new BehaviorSubject<boolean>(true);
public toggleLabels() {
this.toggleLabels$.next(!this.toggleLabels$.getValue());
}
我只是得到反向值并将其推回。好方法吗?
这对这么简单的事情来说很好,但 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()
使用 scan RxJS 有一个内置的状态管理解决方案,可用于所有状态场景(还有一些比切换机制更复杂的场景)。
Useful for encapsulating and managing state. Applies an accumulator (or "reducer function") to each value from the source after an initial state is established -- either via a seed value (second argument), or from the first value from the source.
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 提到我的回答没有完全按照问题逻辑实现行为。有两个概念上的区别:
- 新订阅者不会得到最后的值
- 没有订阅者意味着 observable 不会 calculate/emit 它的管道
对于这两个缺失的功能,如果需要,有一个特定的解决方案:
新订阅者(重播最后一个值):
shareReplay 运算符允许您共享一个可观察对象并重播最后发出的值
Share source and replay specified number of emissions on subscription.
没有订阅者(管道不会发出): connectable 为您创建一个提供 connect
方法的可观察对象。可以调用它来使您的 observable 变热并被订阅。然后它将在没有订阅的情况下发出值。
信息: 大多数时候不需要这两个功能(重播和连接)。在我的上一个项目中,我们看到了过度使用 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>
做一个切换变量有多正确?
public toggleLabels$ = new BehaviorSubject<boolean>(true);
public toggleLabels() {
this.toggleLabels$.next(!this.toggleLabels$.getValue());
}
我只是得到反向值并将其推回。好方法吗?
这对这么简单的事情来说很好,但 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()
使用 scan RxJS 有一个内置的状态管理解决方案,可用于所有状态场景(还有一些比切换机制更复杂的场景)。
Useful for encapsulating and managing state. Applies an accumulator (or "reducer function") to each value from the source after an initial state is established -- either via a seed value (second argument), or from the first value from the source.
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 提到我的回答没有完全按照问题逻辑实现行为。有两个概念上的区别:
- 新订阅者不会得到最后的值
- 没有订阅者意味着 observable 不会 calculate/emit 它的管道 对于这两个缺失的功能,如果需要,有一个特定的解决方案:
新订阅者(重播最后一个值): shareReplay 运算符允许您共享一个可观察对象并重播最后发出的值
Share source and replay specified number of emissions on subscription.
没有订阅者(管道不会发出): connectable 为您创建一个提供 connect
方法的可观察对象。可以调用它来使您的 observable 变热并被订阅。然后它将在没有订阅的情况下发出值。
信息: 大多数时候不需要这两个功能(重播和连接)。在我的上一个项目中,我们看到了过度使用 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>