🚀[FEATURE]: Action status stream listener decorators
Great library, im really finding ngxs's clean and straightforward approach a joy to write with
I'm submitting a...
[ ] Regression (a behavior that used to work and stopped working in a new release)
[ ] Bug report
[ ] Performance issue
[x] Feature request
[ ] Documentation issue or request
[ ] Support request => https://github.com/ngxs/store/blob/master/CONTRIBUTING.md
[ ] Other... Please describe:
Current behavior
As far as i know this is the only way to subscribe to an action status
this.actions$.pipe(ofActionSuccessful(CartDelete)).subscribe(...)
Expected behavior
It would be neat if we could do this
@Action(ReadReport)
readReport(ctx: ReportStateContext) {
ctx.patchState({ isLoading: true });
return this.reportsService
.getReports();
}
@ofActionSuccessful(ReadReport) // automatically called as part of action lifecycle
readReportSuccess(ctx: ReportStateContext, data: Data) {
ctx.patchState({ data });
}
@ofActionFailure(ReadReport) // automatically gets called if ReadReport action throws error
readReportFailure(ctx: ReportStateContext, error: Error) {
ctx.patchState({ error });
}
This would reduce the boilerplate for traditional actions declarations and allows us to hook into the ngxs action stream more easily.
I like the concept but the tricky thing is that dispatching the action is a multicast.
ie. The ReadReport action could be handled by multiple states, and could even be handled multiple times within this state. How would the value of data be determined? It would represent multiple return values.
I could foresee a syntax like this:
@Action(ofActionSuccessful(ReadReport))
But the value of the result is still a bit difficult to assertain.
Ah i didn't see that the ofActionSuccessful pipeable operator doesn't actually deliver a value in its stream...
Yea i would rather use the ngxs built in action statuses than have to dispatch success and failure actions for every request.
On a side note, do you recommend using the patter of dispatching success and failure actions as a result of a request? eg.
ReadReport = '[Report] read report';
ReadReportSuccess = '[Report] read report success';
ReadReportFailure = '[Report] read report failure';
@futbotism https://github.com/ngxs-labs/emitter#lifecycle
what do you think about the simplified use of the actions
I did have a look at this pattern, and the simplification looks appealing, but i'm reluctant to move away from redux currently
@futbotism
IMHO you could centralize everything in one place without the need to listen to ofActionSuccessful | ofActionErrored that might have side effects. NGXS can easily handle asynchronous actions.
Look at the code below:
@Action(ReadReport)
readReport(ctx: ReportStateContext) {
ctx.patchState({ isLoading: true });
return this.reportsService.getReports().pipe(
tap((data) => ctx.patchState({ data }))
catchError((error) => {
ctx.patchState({ error });
return throwError(error);
}),
finalize(() => ctx.patchState({ isLoading: false }))
);
}
Or using async/await:
@Action(ReadReport)
async readReport(ctx: ReportStateContext) {
ctx.patchState({ isLoading: true });
try {
const data = await this.reportsService.getReports().toPromise();
ctx.patchState({ data });
} catch (error) {
ctx.patchState({ error });
throw error;
} finally {
ctx.patchState({ isLoading: false });
}
}
@arturovt I think we update example into documentation
@markwhitfeld https://stackblitz.com/edit/ngxs-of-manage-operation
Duplicate https://github.com/ngxs/store/issues/488