State management is one of the most difficult tasks in front-end development. In Angular2 we are presented with a number of options. The most promising ones seem to be holding reusable state in services vs. using the ngrx/store library specifically designed to help with state management. Here are my current views on the pros and cons of each approach, prioritized:
Pros of using ngrx/store
- Dev Tools
- You have a clear methodology => Other people joining your project will know how to handle state if they know ngrx (or redux or similar), and if not, they know where to inform themselves.
Cons of using ngrx/store
- You’re adding an extra library. Could become deprecated, badly maintained or have breaking changes all the time. For example, we couldn’t update our project to Angular 5, because ngrx was lagging behind. Also, updating from ngrx/store v2 to nrgrx/store v4 took one afternoon, and that was for a small project.
-
Name-spacing is ugly, e.g.
'[heroes] UPDATE'
. What happens if you choose the same action name by accident? The answers aren’t really satisfying. With services you’ll get better autocompletion: heroService.updateHero(hero) instead ofdispatch({type: '[heroes] UPDATE', hero})
. Of course you could put the dispatch also in a heroService, but then you’ll have more boilerplate.
Pros of using services as your store
- No extra library needed, it’s core Angular
- You don’t have one global state, so you can better modularize. For example you can have a reusable UserModule, that doesn’t know anything about the other parts of the state of your app.
- No name-spacing problems as every resource has it’s own service
- Complete flexibility in use. You can throw immutability overboard, if you want.
Cons of using services as your store
- No-one tells you how to do it, no standards
Other opinions
Here are also some opinions on this topic from other people. mean.studio says:
Despite common opinion, ngrx gets hard to maintain and I have seen a lot of spaghetti code which triggers each other and it gets really messy. Despite people assumes that there is only one way to set up ngrx/redux, I have seen tons of different ways which all of then end up to be faulty and need to be rewritten from scratch. Ngrx uses a lot of boilerplate code which is not necessary for most of cases. Some concepts like reducers are totally wrong. In apps I always see list of items, merely I need to apply something to single item. Mappers and filters are good in case you need transform all or portion of data.
while James Trefry sees more benefits in using ngrx:
Here are some other pros of NgRx or NGXS (less boilerplate).I think services are best for simple apps, but as complexity grows, you will be wishing you had controls to reign in the resulting chaos.
- You can hydrate your entire application with a single JSON object – useful for debugging, testing, or returning the user to the exact state they had previously.
- Single point of entry allows complete logging and interception/filtering/modification of actions.
- A standard for state management allows the community to provide useful plugins. https://ngxs.gitbook.io/ngxs/plugins
bastien on the other hand doesn't think ngrx adds enough value:
I also go with the shared/singleton services without using observables because in 99% of the cases you do not need them to react to changes
Conclusion
I still prefer the manual approach with services. I think it adds a lot to the flexibility and simplicity that you can shape your data-store as you need it. Often you don’t need the entire store store to be an observable and you can easily extend your store-services to make them observables once you need that feature. For example I’d rather have a store with the signature
heroStore: {[heroId: string]: BehaviorSubject<Hero>}
than the signature
heroStore: BehaviorSubject<{[heroId: string]: Hero}>
As long as I don’t need something like the total number of heroes it’s completely sufficient to have the first signature. And in case I suddenly need the store as an observable in my app, I can still easily change the service.
Also the mistakes in the docs and an example-app that’s far from real-world scare me a bit.