I'm new to RxJS and wondering about internal state.
Our use case is a promise that returns an initial state (a list of items with ids) and an observable that streams mutations (deleted ids) to that state. The updated list of items is then a persistent state and should be used in building the result.
I can hack something together using a global variable but as expected it behaves weirdly:
import { combineLatest, from } from "rxjs";
import { startWith } from "rxjs/operators";
...
const initialObservable = from(initialPromise);
const mutationObservableWithStart = mutationObservable.pipe(startWith(null));
const globalDeletedIds: string[] = [];
return combineLatest([initialObservable, mutationObservableWithStart]).pipe(
map(([items, mutation]) => {
if (mutation && mutation.deleted) {
globalDeletedIds.push(mutation.id);
}
const currentItems = items.filter(doesNotIncludeIds(globalDeletedIds));
return buildResult(currentItems);
})
);
My question is: how to correctly manage internal state in an observable?
If I understand the problem right, I would proceed like this (inline comments try to explain the logic)
// first we start the stream with the initial list of items (an array notified
// by the initialObservable)
initialObservable.pipe(
// once initialObservable notifies the list we switch to another observable
switchMap(items => {
// the stream we switch to starts with the stream of mutations
return mutationObservable.pipe(
// we need to notify something since the very beginning, not only from
// when the first mutation occurs, therefore we use startWith to say
// that the new stream starts immediately notifying a null (assuming
// there is no null key in items)
startWith(null),
// since we need to keep a state but also to notify the state any time
// an event from upstream (i.e. a mutation) occurs, then we use the
// scan operator which holds an internal state which is notified any time
// upstream notifies something
scan((state, m) => {
// the state, i.e. the list of items, gets updated according to the
// mutations received from upstream
state = state.filter(item => item.id !== m)
// scan returns a new state
return state
}, items) // the state is initialized with the items received
)
})
)
You can take a look at this stackblitz for an example.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.