rxjs-如何从一个可观察对象创建另一个可观察对象,但忽略其父可观察对象中的输出?

rxjs-如何从一个可观察对象创建另一个可观察对象,但忽略其父可观察对象中的输出?,rxjs,rxjs-observables,rxjs-pipeable-operators,Rxjs,Rxjs Observables,Rxjs Pipeable Operators,我有一种情况,我有一个可观察的,对于每个发出的项目,我想创建另一个可观察的,但忽略该可观察的值,而是返回第一个可观察的结果。 例如,如果我单击一个按钮,我想跟踪在另一个按钮中发生的事情,只有在第一个按钮打开时 我现在可以通过一种技巧做到这一点,通过获取子对象的输出,并将其与父对象的值一起传送到mapTo。您可以在以下代码中看到它,它可以在: 从rxjs导入{fromEvent,from}; 从rxjs/operators导入{mapTo,switchMap,tap,scan}; const bu

我有一种情况,我有一个可观察的,对于每个发出的项目,我想创建另一个可观察的,但忽略该可观察的值,而是返回第一个可观察的结果。 例如,如果我单击一个按钮,我想跟踪在另一个按钮中发生的事情,只有在第一个按钮打开时

我现在可以通过一种技巧做到这一点,通过获取子对象的输出,并将其与父对象的值一起传送到mapTo。您可以在以下代码中看到它,它可以在:

从rxjs导入{fromEvent,from}; 从rxjs/operators导入{mapTo,switchMap,tap,scan}; const buttonA=document.getElementByIda; const buttonB=document.getElementByIdb; const textA=document.querySelector'textA'; const textB=document.querySelector'textB'; 从EventButtona,“单击”。管道 //这将切换活动或不活动。 scanactive=>!主动,假,, switchMapactive=>{ 如果激活{ 常量按钮单击$=fromEventbuttonB,‘单击’; //在这里,我们可以观察按钮b的点击,当按钮a被打开时。 返回按钮单击$管道 //计算自按钮a打开以来按钮b的点击总数。 扫描计数=>count+1,0, 点击按钮计数=>{ textB.value=`按钮b计数${ButtonCount}`; }, //忽略最终可观察输出的按钮b计数值。 mapToactive }否则{ textB.value=`; 从[活动]返回; } } .订阅{ 下一步:按钮活动=>{ textA.value=`按钮a活动:${ButtonActivity}` } }; 这里有几个问题。如果按钮处于打开状态,则外部可观察对象仅在单击按钮后接收一个值。 这张地图看起来很粗糙


有更好的方法吗?

听起来你根本不想让内在的可观察性成为过程的一部分。你在等它还是什么

如果没有,您可以将其全部作为副作用,如下所示:

从EventButtona,“单击”。管道 scanactive=>!主动,假,, tapactive=>{ifactive{ 从EventButtonB,“单击”。管道 扫描计数=>count+1,0, 点击按钮计数=>{ textB.value=`按钮b计数${ButtonCount}`; } 订阅 }} .订阅{ 下一步:按钮活动=>{ textA.value=`按钮a活动:${ButtonActivity}` } }; 嵌套订阅被认为是不好的巫毒,因此您可以像这样重构,以保持更明显的客户分离:

const trackActiveFromButton$=FromEventButton“单击”。管道 scanactive=>!主动,假,, 共享1 ; trackActiveFromButton$。订阅{ 下一步:按钮活动=>{ textA.value=`按钮a活动:${ButtonActivity}` } }; trackActiveFromButton$.pipe switchMapactive=>active? 从EventButtonB,“单击”。管道 扫描计数=>count+1,0, 点击按钮计数=>{ textB.value=`按钮b计数${ButtonCount}`; } : 空的 订阅
听起来你根本不想让内在的可观察性成为过程的一部分。你在等它还是什么

如果没有,您可以将其全部作为副作用,如下所示:

从EventButtona,“单击”。管道 scanactive=>!主动,假,, tapactive=>{ifactive{ 从EventButtonB,“单击”。管道 扫描计数=>count+1,0, 点击按钮计数=>{ textB.value=`按钮b计数${ButtonCount}`; } 订阅 }} .订阅{ 下一步:按钮活动=>{ textA.value=`按钮a活动:${ButtonActivity}` } }; 嵌套订阅被认为是不好的巫毒,因此您可以像这样重构,以保持更明显的客户分离:

const trackActiveFromButton$=FromEventButton“单击”。管道 scanactive=>!主动,假,, 共享1 ; trackActiveFromButton$。订阅{ 下一步:按钮活动=>{ textA.value=`按钮a活动:${ButtonActivity}` } }; trackActiveFromButton$.pipe switchMapactive=>active? 从EventButtonB,“单击”。管道 扫描计数=>count+1,0, 点击按钮计数=>{ textB.value=`按钮b计数${ButtonCount}`; } : 空的 订阅 有更好的方法吗

根据您的口味,下面的可能更好。在我看来,您的示例代码变得有点混乱,因为您有一个单独的可观察对象,它试图做太多的事情。副作用在某种程度上与流行为逻辑混合在一起

使用tap来做副作用类型的事情是完全可以的,但有时它会让人更难理解。特别是在上面的代码中,因为涉及到嵌套的可观察对象

创建总是发出特定数据的单独观察对象可以使事情更容易理解

如果我们声明一个流来表示isActive状态,并订阅该流以更新textA,以及 定义一个计数器流来表示isActive=true时发生的单击次数,使用该值来更新textB,我认为这会使跟踪发生的情况变得更容易:

const clicksA$ = fromEvent(buttonA, 'click');
const clicksB$ = fromEvent(buttonB, 'click');

const isActive$ = clicksA$.pipe(
  scan(active => !active, false),
  startWith(false)
);

const counterB$ = combineLatest([isActive$, clicksB$]).pipe(
  scan((count, [isActive]) => isActive ? count + 1 : -1, 0)
);
   
counterB$.subscribe(
  count => textB.value = count === -1 ? '' :`button b count ${count}`
);

isActive$.subscribe(
    isActive => textA.value = `Button a active: ${isActive}`
);
对我来说,单独定义流可以更容易地看到它们之间的关系,也就是说,更容易判断它们何时会发出:

isActive源于clicksA 计数器B源于clicksB&isActive 这是一张工作票

此外:

外部可观察对象仅在单击按钮后接收值

可以使用发出默认值来解决此问题

有更好的方法吗

根据您的口味,下面的可能更好。在我看来,您的示例代码变得有点混乱,因为您有一个单独的可观察对象,它试图做太多的事情。副作用在某种程度上与流行为逻辑混合在一起

使用tap来做副作用类型的事情是完全可以的,但有时它会让人更难理解。特别是在上面的代码中,因为涉及到嵌套的可观察对象

创建总是发出特定数据的单独观察对象可以使事情更容易理解

如果我们声明一个流来表示isActive状态,并订阅该流来更新textA,并定义一个计数器流来表示isActive=true时发生的点击次数,使用该值来更新textB,我认为这会使跟踪发生的情况变得更容易:

const clicksA$ = fromEvent(buttonA, 'click');
const clicksB$ = fromEvent(buttonB, 'click');

const isActive$ = clicksA$.pipe(
  scan(active => !active, false),
  startWith(false)
);

const counterB$ = combineLatest([isActive$, clicksB$]).pipe(
  scan((count, [isActive]) => isActive ? count + 1 : -1, 0)
);
   
counterB$.subscribe(
  count => textB.value = count === -1 ? '' :`button b count ${count}`
);

isActive$.subscribe(
    isActive => textA.value = `Button a active: ${isActive}`
);
对我来说,单独定义流可以更容易地看到它们之间的关系,也就是说,更容易判断它们何时会发出:

isActive源于clicksA 计数器B源于clicksB&isActive 这是一张工作票

此外:

外部可观察对象仅在单击按钮后接收值

可以使用发出默认值来解决此问题