State Management Libraries
The approaches we have discussed in the two previous lessons are quite good and scale reasonably well:
- For local state, use streams defined directly as class members on the component (or in a service dedicated to that component)
- For shared state, use streams defined in a shared service
Why would we ever want or need to use anything else?
You might not need or want to. These approaches can be used for simple applications, but even as applications become extremely complex these methods remain viable… you just need to be more careful/intentional about what you are doing.
The key reason to use a state management library in my opinion is the opinions and structure they provide. Usually, using most state management libraries is going to be harder than just using a service with a subject. They will have their own special syntax/concepts that you need to learn before you can be effective with it.
However, this is the very thing that makes state management libraries a good idea. The designers of these libraries have considered and implemented what they think is a good approach to managing state in a variety of situations (and these libraries are generally built by people who have a very good idea of what they are doing). If you are rolling with your own solution, it might seem simple at first, but eventually you are going to be making all these little architectural decisions on how to manage your state. Over time, if you are not careful, or if there are unforeseen dangers you haven’t considered, you could end up with a messy and buggy approach to state management.
This is doubly bad if you are working in a team environment. If you are just going with your own state management approach, you need to make sure the team is on board with all of the ideas and that everyone is implementing things the same way. By not using a pre-built state management library, you are effectively designing your own ad-hoc state management system perhaps without even realising it. Using streams in a service for shared state is a nice approach, but there are still some decisions to be made around exactly how you are going to implement your service with a subject approach.
However, if you use a pre-built solution, all of the approaches/concepts are baked in by default. Your entire team can easily be on the same page with how to manage state, because the approach has already been determined and is generally well documented by the library creators/contributors.
The tricky thing with state management libraries is that there are so many options, and it is an area that is very preference based. Some people will swear by one solution, and others will hate it with a passion.
I would recommend focusing a little on getting the basic Angular concepts down before diving into state management libraries, you won’t need them right away. However, once you do have a bit of experience under your belt, I do think state management libraries are a good way to continue learning and exploring more concepts you might not have thought about.
Popular Libraries
For the rest of this lesson, I am going to briefly cover some of the popular state management libraries for Angular. I will start with the ones I use and know the most about, because I have experience with them and can give a little more insight into them, but don’t take this as meaning that these approaches are necessarily the best. This just happens to be what I like.
NgRx Component Store
If you are not new to Angular then maybe you have heard of NgRx already. When people refer to NgRx they generally mean NgRx Store specifically, which has quite a reputation for being complex. However, NgRx is a collection of libraries, and NgRx Store is just one of those.
Whilst NgRx Store has a reputation for being complex, NgRx Component Store is quite the opposite. It is an extremely lightweight state management solution that is primarily intended to manage local state for components, but it can also be used as a simple global store for shared state.
NgRx Component Store is pretty much all I use these days when I reach for a state management library - I like it because it is simple, but it is also flexible and powerful enough for pretty much every situation. It also integrates very well with a reactive/declarative approach to building Angular applications.
In the lesson on local state, we already covered the idea of creating a service and providing it to just one component, e.g:
@Component({
selector: 'app-checklist',
templateUrl: './checklist.page.html',
styleUrls: ['./checklist.page.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [ChecklistItemStore],
})
This is the general idea behind Component Store as well - we will create a service (we will call it a “store”) and we provide that to a single component. However, the service we create with Component Store will be a little special:
export interface MoviesState {
movies: Movie[];
}
@Injectable()
export class MoviesStore extends ComponentStore<MoviesState> {
constructor() {
super({movies:[]});
}
readonly movies$: Observable<Movie[]> = this.select(state => state.movies);
}