RxJS-如何在操作后访问BehaviorSubject的值

问题描述 投票:-1回答:4

假设我有一个行为主体,通过一两个操作来管道:

const inputNumber = new BehaviorSubject(2);

// The current number can be retrieved with `inputNumber.getValue()`

const numberAfterOperations = inputNumber.pipe(
  filter(a => (a+1) % 2), // filter out odd numbers
  map(a => a * a), // square it
);

如何访问numberAfterOperations的值?

// Does not work because `getValue` is not defined!
numberAfterOperations.getValue(); // I expect this to be 4

inputNumber.next(4);

// Does not work!
numberAfterOperations.getValue(); // I expect this to be 16

注意:此处的可观察订阅工作正常。我问同步访问.value(或.getValue()

我在这里注意到了类似的问题,但没有看到解决方案:https://github.com/ReactiveX/rxjs/issues/2378

javascript rxjs rxjs6
4个回答
1
投票

我觉得你对Observables / Subjects的工作原理感到困惑。在您显示的示例中,Subject不保留值4或16,这些值是通过生成的observable应用您的管道操作得出的。您将不得不使用像first()take(1)这样的运算符来在主题上调用next之间获取值。主题只知道通过next通过它发送的值,它不知道可能附加到它的可观察量如何决定修改该值。


0
投票

Observable.pipe()返回Observable,因此如果你想访问实际的BehaviourSubject,你也必须通过它。

const inputNumber = new BehaviorSubject(2);

// The current number can be retrieved with `inputNumber.getValue()`

const numberAfterOperations = inputNumber.pipe(
  filter(a => (a+1) % 2), // filter out odd numbers
  map(a => a * a), // square it
  map(n => [n, inputNumber])
);

// ...later

numberAfterOperations.subscribe(([number, subject]) => {
  sbject.next(n/2);
});

但这不应该做,你可以清楚地看到反模式。将.next变成一个单独的方法并在需要的地方导入它。


0
投票

Pipe设置了一个新的observable,它在订阅之前不做任何事情。使用getValue可以访问该值不是行为主题。你必须订阅它,或者它是一个冷可观察的,并且根本没有数据在流下。在地图函数中放置一个console.log,如果没有订阅,你会发现它甚至都没有被调用。

如果您100%确定订阅将同步运行,如果从BehaviorSubject派生,则可以编写解包函数,但如果传入异步observable,结果将是不可预测的,很可能返回undefined。

const { BehaviorSubject } = rxjs;
const { filter, map } = rxjs.operators;

const inputNumber$ = new BehaviorSubject(2);

const numberAfterOperations$ = inputNumber$.pipe(
  filter(a => (a+1) % 2), // filter out odd numbers
  map(a => { console.log('mapping'); return a * a; }), // square it
);

inputNumber$.next(4);

console.log('No mapping has happened yet');

console.log(unwrap(numberAfterOperations$));

function unwrap(obs$) {
  let value;
  const sub = obs$.subscribe(val => { value = val; });
  sub.unsubscribe();
  return value;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.4.0/rxjs.umd.min.js"></script>

如果您使用的是Angular,则可以在视图中使用异步管道

{{ numberAfterOperations | async }}

0
投票

伙计们,谢谢你的回答。你帮助我意识到没有内置的方法可以用行为主题做我想做的事。我结束了以下情况:

function mapBehaviorSubject(behavior, mapFn) {
  const mappedSubject = new BehaviorSubject(mapFn(behavior.getValue()));
  behavior.subscribe({
    next: value => mappedSubject.next(mapFn(value)),
  });
  return mappedSubject;
}

这允许我有所需的行为:

const inputNumber = new BehaviorSubject(2);

const numberAfterOperations = mapBehaviorSubject(inputNumber, x => x * x);

这允许我有一个持久的主题,其映射值与getValue()同步可用。

© www.soinside.com 2019 - 2024. All rights reserved.