Closed samuelstroschein closed 1 month ago
@jan.johannes @martin.lysk1 input desired
@jan.johannes i suspect we will choose the same pattern we decide on here in the lix sdk
Option 3, if plugins depends on settings
, we can also model that in setSettings
Updates after 2 hours of banging my head against the wall:
Observables can't be used for state as they don't hold their last value. Correctly modeling reactive state entails the avoidance of re-triggers. That goes against Observables which are modeled as streams (of events).
Which means that BehaviourSubject
must be used. BehaviorSubject
however can't model derived state. Hence, implicit dependent state (option 2 and 3) is the only option with RxJS. That will surely lead to chaos down the road. Someone forgot that X triggers Y, or Y is not awaited as a result of X, etc.
I am going with approach number 3 to solve this ticket but I am confident in the long term viability. Ideally, we have a state management solution that has a first class concept of derived state.
As an example of explicit derived state: I wouldn't know how to model project.errors
with an implicit model.
Declarative derived state
const errors$ = merge(
pluginErrors$,
userErrors$
otherErrors$
)
Implicit derived state
const errors$ = new BehaviorSubject([]);
pluginsErrors$.subscribe((errors) => {
errors$.next([...errors, ...$userErrors.getValue(), ...$otherErrors.getValue()]);
}
userErrors$.subscribe((errors) => {
errors$.next([...errors, ...$pluginErrors.getValue(), ...$otherErrors.getValue()]);
}
otherErrors$.subscribe((errors) => {
errors$.next([...errors, ...$pluginErrors.getValue(), ...$userErrors.getValue()]);
}
Edit: Ugh no it's just share
. Now the shareReplay
makes sense.
I did find a solution to RxJS observables that should save their last state. shareReplay
is what we are looking for https://rxjs.dev/api/index/function/shareReplay.
Off-topic the jargon that RxJS uses is … unintuitive. shareReplay
, really? Why not call it shareLastValue
. What's the replay supposed to indicate?
Another one is distinctUntilChanged
. In code it reads more like a onlyTriggerIfChanged
though. Next to distinct
, distinctUntilChangedKey
and what not. Huge API. For unknown reasons distinctUntilChanges
isn't even triggered. Cool.
Did some more research. If awaiting side-effects is important, a state solution needs a concept of "computing". RxJS (and Effector) emits event A with no knowledge if event B is about to happen.
The knowledge that event B is about to happen can be used to "await" event B. RxJS is getting close with the concept of a "completed" observable and the await takeLastValue
function. Unfortunately, complete kills the subscriptions. Hence, awaiting a side effect is possible but only once.
@jan.johannes can you elaborate or we can sync quickly in around?
Context
State like
project.plugins
depends onproject.settings
. We have different ways to model the dependency. I am unsure which one is the way to go.Options