代码之家  ›  专栏  ›  技术社区  ›  BizzyBob

RXJS-行为主题:正确使用。价值

  •  1
  • BizzyBob  · 技术社区  · 6 年前

    我想知道它是否真的有正确的用途 behaviorSubject.value .根据 this answer ,我们只能通过订阅获取值。

    在我看来没问题的情况是我在使用 .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 source 上述答案,这两种方法的区别在于 价值 将在以下情况下抛出:

    • 这个课题已经完成了
    • 出现了一个错误

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

    这是一个有效的用例吗 行为主体。价值 ? 还有其他的吗?

    另一个似乎可以使用 价值 根据之前发出的值构造新对象时:

    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);
    }
    

    有什么我忽略的顾虑吗?

    1 回复  |  直到 6 年前
        1
  •  8
  •   Jonathan Stellwag    4 年前

    1.布尔示例 subscribe 以及 .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.反应式编程

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

    reactivex.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);

    这个 价值 对你的代码做一件重要的事情,这与干净的反应式解决方案不同。 业务逻辑被移到流之外的toggle函数中。 正如官方文件所提到的,rxjs的目标是拥有干净的输入/输出。这意味着 input 你给你的流总是一样的 output .这意味着您的转换应该在流中处理,没有任何副作用。

    3.副作用的负面影响

    • 更难的测试(模仿)
    • 难以理解的影响
    • 难以扩展的功能(代码建立在动作的基础上,不注重效果)

    4.使用rxjs可以更轻松地解决的问题

    • 随时间变化的异步/线程化数据(取消、暂停等)
    • 操作员
    • 轻松组合不同的流(帮助你专注于应该发生的事情,而不是什么时候)
    • 并发(流的轻松拆分和合并)

    5.我自己的意见

    反应式编程为您解决了几个问题,或者至少让它变得更容易。在您展示的示例中,我不明白为什么需要使用反应式编程。如果你能避免 rxjs 和程序 toggle() 充分地 imperative .但是当你决定和一个 BehaviorSubject 你决定做反应式编程。

    6.总结

    can 通过使用 价值 但是你 should not .

        2
  •  2
  •   ch_g    6 年前

    我建议您避免在代码中直接管理状态。它超出了使用Rx的目的。

    在您的示例中,当特定事件发生时,会调用“切换”,对吗? 你只需要通过一个可观察的事件来跟踪特定的事件,然后使用“扫描”将这些事件流转换为一个状态流。

    下面是一个例子,我使用一个数字数组来模拟切换事件,并假设初始状态为“true”:

    Rx.Observable.from([1,1,1,1])
      .pipe(
         scan((acc,_) => !acc, false)
       ).subscribe(st => console.log(st))  
    

    输出将是- 符合事实的 错误的 没错, 错误的

    这里的关键是把每件事都看成是一连串的事件。在Rx lib的帮助下,您可以轻松地转换和制作这些流来实现您的逻辑。

        3
  •  0
  •   HTN    6 年前

    我不知道你的用例,但通常情况下,你不应该使用 toggle() 不带参数,但设置值:

    setValue(v: boolean) {
       this.myBoolSubject.next(v);
    }
    

    调用方应该始终知道要设置什么值。在你真的不想给出价值的特殊情况下,使用 .value 很好。

        4
  •  0
  •   onik    6 年前

    使用它没有问题 BehaviorSubject.value ,你可以随时使用它。在您的例子中,肯定要使用value属性,因为您已经将更改行为封装到了方法中,所以您可以在内部获取该值,而无需担心

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