I have the following Subject:
private active = new Subject<P>();
prev: Custom<any>;
set(p: P): void {
this.active.next(p);
}
I want to extract data from active
subject and set it to prev
like this:
set(p: P): void {
this.prev = this.active;
this.active.next(p);
}
How to do that?
You're better off using BehaviorSubject
here. It holds the current value and also has value
getter to get it.
private active = new BehaviorSubject<P>(null); // <-- default value required
prev: Custom<any>;
set(p: P): void {
this.prev = this.active.value;
this.active.next(p);
}
But this doesn't actually look so clean. How exactly are you intending to use the prev
value? Perhaps there's a cleaner way using ReplaySubject
with buffer 2.
.value
getterI could come up with 2 ways to use the previous value from a stream.
pairwise
operator. It'll emit the last value and current value as an array. One down side it doesn't emit the first value since there is no current previous state yet. It could be adjusted with the startWith
operator.import { Subject } from "rxjs";
import { startWith, pairwise} from "rxjs/operators";
export class AppComponent {
subSource = new Subject<any>();
sub$ = this.subSource.pipe(
startWith(null),
pairwise()
);
constructor() {
this.sub$.subscribe(val => console.log("pairwise:", val));
this.subSource.next(1);
this.subSource.next(2);
this.subSource.next(3);
}
}
// expected output:
// pairwise: [null, 1]
// pairwise: [1, 2]
// pairwise: [2, 3]
ReplaySubject
with buffer 2 and use scan
operator to emit only previous and current values.import { ReplaySubject } from "rxjs";
import { scan } from "rxjs/operators";
export class AppComponent {
replaySubSource = new ReplaySubject<any>(2);
replaySub$ = this.replaySubSource.pipe(
scan((acc, curr) => {
acc.push(curr);
return acc.slice(-2);
}, [])
);
constructor() {
this.replaySub$.subscribe(val => console.log("replay subject:", val));
this.replaySubSource.next(1);
this.replaySubSource.next(2);
this.replaySubSource.next(3);
}
}
// replay subject: [1]
// replay subject: [1, 2]
// replay subject: [2, 3]
Working example: Stackblitz
As for the question about the default value using find
. No I don't think it's dirty to use find
there. In fact, find
is there to fetch a specific element based on a predicate, so I don't see any wrong in your usage.
{prev: .., active: ..}
.You need only to pipe in a map
operator to the end and emit as per the requirement.
sub$ = this.subSource.pipe(
startWith(null),
pairwise(),
map(([prev, active]) => ({ prev: prev, active: active }))
);
// expected output:
// pairwise: {prev: null, active: 1}
// pairwise: {prev: 1, active: 2}
// pairwise: {prev: 2, active: 3}
I've also adjusted the Stackblitz to reflect the changes.