首页 > 解决方案 > RXJS - BehaviorSubject:正确使用 .value

问题描述

我想知道是否真的有适当的用途behaviorSubject.value。根据这个答案,我们应该只通过订阅来获取值。

对我来说似乎没问题的情况是我使用.value来确定通过流推送的下一个值,例如当我切换一个简单的布尔值时:

myBoolSubject = new BehaviorSubject(false);

toggle() {
  this.myBoolSubject.next(!this.myBoolSubject.value);
}

替代使用subscribe()看起来像:

toggle() {
   this.myBoolSubject.pipe(take(1)).subscribe(
      val => this.myBoolSubject.next(!val)
   );
}

通过查看rxjs 源代码和上述答案,这两种方法之间的区别在于.value

在这个简单的例子中,我不会完成这个主题,我不认为错误是一个问题,因为我只是通过这个主题推动简单的布尔值。

这是一个有效的用例behaviorSubject.value吗?还有其他人吗?

另一种似乎可以使用.value的情况是从先前发出的值构造新对象时:

private state = new BehaviorSubject<State>(INITIAL_STATE);
public state$ = this.state.asObservable();

public updateState(changes: Partial<State>){
    const newState = {...this.state.value, ...changes};
    this.state.next(newState);
}

另一种方法是将最新的状态发射缓存在另一个变量中,如下所示:

private _state = INITIAL_STATE;
private state = new BehaviorSubject<State>(INITIAL_STATE);
public state$ = this.state.asObservable();

public updateState(changes: Partial<State>){
    const newState = {...this._state, ...changes};
    this.state.next(this._state = newState);
}

有什么我忽略的问题吗?

标签: angularrxjs

解决方案


subscribe1. 没有和使用的布尔示例.value

const { Subject } = rxjs;
const { scan, startWith } = rxjs.operators;

myToggle$$ = new Subject();

myBool$ = myToggle$$.pipe(
  scan((acc) => !acc, false),
  startWith(false)
)

myBool$.subscribe(v => console.log('result: ', v));

myToggle$$.next();
myToggle$$.next();
myToggle$$.next();
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.3/rxjs.umd.min.js"></script>

2.反应式编程

避免复杂的有状态程序,在可观察的流上使用干净的输入/输出函数。

反应式x.io

您已经在使用 rxjs,您也可以说,您想使用直接的命令式代码:

myBool = false;
function myToggle() { myBool = !myBool }

console.log('result: ', myBool);
myToggle();
console.log('result: ', myBool);
myToggle();
console.log('result: ', myBool);
myToggle();
console.log('result: ', myBool);

对你的.value代码做了一件重要的事情,它不同于一个干净的反应式解决方案。业务逻辑从流中移到切换函数中。正如官方文档提到的那样,rxjs 的目标是拥有干净的输入/输出。这意味着input你给你的每一个流接收总是相同的output。这意味着您的转换应该在流内部处理,没有任何副作用。

3.副作用的缺点

  • 更难的测试(嘲笑)
  • 难以理解的影响
  • 难以扩展功能(代码建立在动作之上,而不是专注于效果)

4. 使用 rxjs 更容易解决的问题

  • 随着时间的推移异步/线程数据(取消,暂停,..)
  • 运营商
  • 不同流的简单组合(帮助您专注于应该发生的事情,而不是什么时候发生)
  • 并发(轻松拆分和合并流)

5.我自己的看法

反应式编程为您处理了几个问题,或者至少使它更容易。在您展示的示例中,我看不出您为什么需要使用反应式编程。如果您完全避免rxjs和编程,那也toggle()完全没问题imperative。但是,当您决定使用 aBehaviorSubject时,您决定使用响应式编程。

6.总结

can通过使用实现您的问题,.value但是您should not


推荐阅读