I really like the Redux concept. It allows developers to avoid state manipulation to be spread across the application, leading to difficult to detect inconsistencies, specially when dealing with asynchronous events such as calls to HTTP services. It is not, however, an easy concept to grasp. It may look like an overthought solution that creates more troubles than it solves. Anyway, I decided to give NgRx a try a couple of months ago. And it wasn't a pleasant experience. Let me tell you why.
Too much boilerplate
Let's start with the boilerplate issue. Whenever I needed to use NgRx for a specific part of my webapp, I had to:
- Create a set of actions
- Create a reducer function with a big and ugly switch statement
- Add the reducer to the
StoreModule.forRoot
orStoreModule.forFeature
call. - Call the
select
function in my component or create selectors to get the current state. - Call the
dispatch
function to dispatch an action.
What if I needed to fetch data from a service? Well, then I'd have to:
- Add an action that will be dispatched when data needs to be fetched
- Add an action that will be dispatched when the call finished successfully
- Add an action that will be dispatched when the call fails
- Add an Effects class that will call the data fetch service itself and do the action dispatching
- Add the Effects class to the
EffectsModule
call
It's not a big problem if it's not often needed. Data feching is what I mostly do, though! Effects can become huge and not so easy to maintain.
Too many concepts
I have to admit, a part of our problem is that developers only knew AngularJS (1.5), not Angular (2+). They had to learn about components, modules, DI. I know AngularJS had them before, but Angular (2+) is so different it feels like a new framework. They also had to learn about RxJS, Observables, and other concepts that aren't trivial. And then, suddenly, they also had to learn about Actions, Dispatchers, Reducers, Effects, Selectors! Maybe I should've seen it coming, but even if they already felt comfortable with Angular, it seems that those concepts aren't easy to grasp unless you knew Redux(-ey) libraries before.
NgRx feels alien to Angular
Whenever I was using NgRx, I felt like maybe it could make more use of Angular. For example, instead of the big and ugly reducer, decorators should be used by default. Some libraries try to solve that problem, but they felt subpar to me, and they sometimes introduced even more complexity, like needing specific work to avoid problems with AOT compilation. If you're using NgRx, I recommend ngrx-actions.
My coworkers had a very, very difficult time "getting" NgRx, and they spent more time trying to understand NgRx along with Angular than developing the application itself. So, we decided to drop NgRx entirely and letting everyone do as they please, because there was a deadline to meet.
Dropping Redux? Not yet!
I didn't quit trying do use Redux-style libraries in my app, but I decided to try the alternatives. Two of them looked more mature and well-tested:
- NgXs: More simple than NgRx, but it still had some specific parts that irritates developers, such as the need to declare an Action and corresponding specific dispatch method in a separate place.
- Akita: Even simpler than NgXs. Instead of actions and dispatchers, just a plain service, even for async calls. Queries are plain observables.
The winner: Akita
Now, let's see what it takes to introduce Akita in a specific project
- Create a store as a class extending EntityStore
- Create a service that injects the store and expose actions as service methods. No need for actions, reducers, dispatchers, annotated methods, etc. Just plain methods that updates the state.
- Create a class extending QueryEntity so we create selectors
- Need to call a HTTP service? No problem, just create a service method.
It could be even easier, but this seems easy enough I can now talk about it without raising many eyebrows. Maybe I will give NgRx or NgXs another chance, but for now I'll stay with the simpler choice.
Top comments (8)
we are currently facing the same problem with ngrx. We have a quite complex angular app that grew over time and now has a ridiculous amount of boilerplate code for ngrx. my biggest fear is that new team members will have a really hard time understanding what is going on. and the biggest problem of all that boilerplate code is that you can't understand what are the vital parts, as the concept is not self-explanatory at all. akita looks like a good alternative.
Did you give Akita a try? How is that working for you?
Yes, we actually did. We switched one single page application completely and will start with the second soon.
So far it's working really well. We were able to reduce complexity and increase maintainability along the way.
Super article!!!
Akita is more awesome than I had imagined. Super easy to implement.
In a nut shell: I simply write my Angular application as usual, with my model & service (http). And Akita fits right in. Tell Akita to use my model and voila!
Let the service pass any data to the store, then the query as the data which can be returned to the component via observable. Even better to use
*ngxSubscribe=
inside a form. Saving form data is easy too. Pass it to the service which updates the store.Hey @joao , I have been working with Angular+NGRX for the last 2.5 years. I think the strongest part of ngrx is the actions. Once we done with one action stream(with side effects), yes its like a boilerplate. To me ngrx is super awsome.
But for a fresher its very difficult to understand.
I recently read about AKITA, yes what you said was absolutely correct and AKITA is super cool. I am trying to migrate my application from ngrx to AKITA.
IMHO NgRx would really benefit from a Akita-like solution that transforms a service into methods in actions+reducers. For a larger project, actions+reducers start multiplying like there's no tomorrow.
There are pet peeves of mine I didn't mention, like the need to declare the reducers in StoreModule (when Angular has builtin Dependency Injection), weird AOT issues when dealing with different libraries, such as ngrx-forms + ngrx-actions.
I would still recommend NgRx to a team that's familiar with React, though.
I think NGRX Entities and NGRX Data solves most of the boilerplate everyone hate so much.
You can use the cli to generate entities just like you do in Akita
"ng generate entity my-entity"
You gain the full redux + redux devtools
Effects are also very well handled in NGRX.
Selectors are now memoized (cache) and they can use rxjs operators of course
Data normalization is also something that comes out of the box when using NGRX.
So I agree that NGRX in the past had a lot of issues and the boilerplate was a mess but it is changing rapidly and in a good direction.
I would still open up the discussion with the team for every new project cause stuff can change over time.
I think right now Ngrx and Akita are very similar. NGRX improves a lot on reducing boilerplate. And NGRX can work with REDUX DEVTOOLS. Akita is a pretty neat library for other framework like vue but in Angular, I think NGRX is still the best choice.