Reference to this twitter thread: https://twitter.com/jsonberrry/status/1199566382716731393
Subject: "injecting the actions service into the component level as a means for propagating success/error states to a presentational layer"
Question from @jdpearce
"“Injecting the actions service...” woah, woah, woah...what?!
Why aren’t you setting a property in the store and selecting that?"
TL;DR answer: it depends, and if I don't need to store scalar information and can derive the information necessary from just signals flowing down an Observable stream, that alleviates some micromanangement and keeps me aligned to that often seen "don't store what you can derive" principle
Answer:
The best use case I have for this is for optimistic updates. Here's a contrived example:
Scenario: A "like" button on a post, you can "like" a post and also remove your "like". Also if it fails, we'll get a toast popup that says you can try again.
When using an event sourcing / CQRS pattern we might get a 201
from the API when interacting with the like button.
That represents that the backend has received and accepted our intention of changing state, but the backend process
has not fully finished yet, instead the API is telling us, "OK, cool, thanks we'll get to that."
In keeping with the "don't store what you can derive" principle often occuring in FRP, I only need to know that there was
an OK
or a NOT OK
signal, I dont' have to store that as scalar data in a state tree, I just need the signal.
In the presentation layer, if the ngrx Action
service is injected,
I can set the "likedness" of a like button as an Observable<boolean>
by using the action service:
postLiked$ = merge(
this.actions$.pipe(
ofType(postLikedRequestAccepted),
mapTo(true),
),
this.actions$.pipe(
ofType(postUnlikedRequestAccepted),
mapTo(false)
)
).pipe(
startWith(false),
)
Also in the presentation layer, or inside of an Effects class, I can utilize a toast service if the API request failed for some reason
// maybe the showing of the toast is an Observable<boolean> too,
// this is just a contrived example
postInteractionFailedEffect$ = this.actions$.pipe(
ofType(postInteractionFailed),
tap(() => this.toastService.getToasty())
)
Now, holding some error state in the state tree is absolutely something I do all the time, but it just isn't necessary in every scenario.
There's definitely been a buncha discussion about this topic on twitter before. I think that @BioPhoton and @timdeschryver both have opinions about it.