YouTube video for this article
I implemented the Angular Movies app shell with StateAdapt and the code decreased by 50%.
What made the difference?
The app shell state was very simple. It was just a boolean for whether the sidenav was open or not.
This made a small difference in RxAngular vs StateAdapt, because RxAngular has to have an object to manage, but StateAdapt can manage anything, so I just had the state be a boolean. It's easy to change later if needed.
Another difference was that RxAngular was wired up in a way where a URL change would cause a method to be called as a side-effect, when it could have been reactive even in RxAngular. I fixed that in StateAdapt though, so I'm sure RxAngular could have been a couple of lines less if it wasn't done that way. But I will always make sure things are as reactive as possible when I use StateAdapt.
Here's the main code for StateAdapt:
urlChange$ = this.router.events.pipe(
filter((e) => e instanceof NavigationEnd),
map((e) => (e as NavigationEnd).urlAfterRedirects),
distinctUntilChanged(),
toSource('urlChange$')
);
sideDrawerOpen = adapt(['app-shell.sideDrawerOpen', false, booleanAdapter], {
setFalse: this.urlChange$,
});
In RxAngular, that false
had to be this:
this.state.set({ sideDrawerOpen: false });
In the template in StateAdapt, I just called the source that's available by default in the sideDrawerOpen
store, but RxAngular has to react to an observable:
this.state.connect('sideDrawerOpen', this.ui.sideDrawerOpenToggle$);
Both implementations have the exact same number of imperative statements: The template has to call .next()
in one case, and set()
in another.
The weirdest part in RxAngular was this:
this.effects.register(
this.router.events.pipe(
filter((e) => e instanceof NavigationEnd),
map((e) => (e as NavigationEnd).urlAfterRedirects),
distinctUntilChanged()
),
() => this.closeSidenav()
);
// ...
closeSidenav = () => {
this.ui.sideDrawerOpenToggle(false);
};
That was the only place the closeSidenav
method was invoked. But that "effect" could just have easily been connected like this:
this.state.connect('sideDrawerOpen', urlChange$, () => false);
// I might be wrong on the exact syntax, but I think that's right.
And all of that was in an init
method that was called imperatively from an ngOnInit
method, which was itself called imperatively by Angular:
init() {
// ...
// RxAngular connections, `set`s, effects
// ...
}
Conclusion
For a full comparison, see this pull request (but please don't open it).
RxAngular is still currently my top pick for state management in Angular. StateAdapt is still a work in progress. I need to apply it to many more projects before I can have the confidence to release version 1.0. If you think it has potential, I'd appreciate a star, and I'd love for you to try it out and share your thoughts.
Thanks!
Top comments (0)