I asked a question a while ago surrounding the @ngrx/effects library but the responses do not resolve my issue entirely.
I am now happy that I understand how actions and effects relate to each other, but I am still unsure as to what functions they perform. The example app goes some way to helping me, but it seems that the effects are doing all the grunt work: the loadCollection$ effect, for example, appears to be loading all of the resources; and a subsequent dispatch of an AddBookSuccessAction appears to add the book to the collection.
In this app, the AddBookAction appears to do nothing in the reducer, but the effect is loading the resource and dispatching a success action.
I guess really what I want to know is about separation of concerns: what should actions be doing, and what should effects be doing?
When you introduce
@ngrx/effectsinto your application, you need to think a little bit differently. Take for example a login component and a user stateWithout using effects, your
loginimplementation might look something likeWhen the
dispatchis called, the action is used by the reducer to update the user state. So the action doesn't really do anything. The reducer can use the payload to update the state, based on the action. The subscribing (in this case)AppComponentwill get the updated user.When you introduce effects, the main difference is how the
loginis handle. Nothing changes about theUSER_UPDATEDaction or the user reducer. What changes is that you introduce another action, that is dispatched by theloginmethod. So now your newloginis simplyNow the purpose of the effect, is to handle what would normally have been handled in the
login. It will listen for theLOGINaction, and then transform itself into theUSER_UPDATEDaction.You can see that from the
LOGINaction, we get the credentials, and useswitchMapto return different Observable, one that contains the new (UPDATED_USER) Action. So it's just a transformation. No one has to call the effect. This is automatically subscribed to.The benefit of doing it this way, is that it makes your component simpler, and easier to test. Also puts all the side effects into one place, which makes it easier to reason about and test. All your components do is subscribe to state and dispatch actions. The effect will handle all the legwork and dispatch the appropriate resulting actions.
As far as the "Action Classes", these are not mandatory. An
Actionis nothing more than an object with two propertiestypeandpayloadthat get passed to the reducer. The purpose of having action classes is to act as action creators. For exampleNow instead of creating the actions yourself, you just call the appropriate method to get the action
You can see the last
mapcall where we create theActionjust be calling theuserActions.updateUser.There are a few benefits to doing this. For one, you get strong typing. When you create the action yourself, there's a chance you might pass the wrong payload. But when you have a method for which you know what the argument type needs to be, you have less chance of a mistake.
Also when you use the action creators, you can accept different arguments. It doesn't have to be the payload. This way you can create the payload yourself (and may introduce some logic) in a reproducible and testable way.
See Also: