What is one of the harder things, if not the hardest, you have done in your Angular applications?
STATE
start small, start local (it is kind of a "must")
...and more (who doesn't like to own a State Management library)
When should we use state management?
– Any Angular developer ever
Do I need to use a Global Store ABorC?
– Any Angular developer ever
FeatureA
FeatureB
FeatureC
StateA
StateB
StateC
App
FeatureA
FeatureB
FeatureC
StateA
StateB
StateC
App
FeatureA
FeatureB
FeatureC
StateA
StateB
StateC
App
FeatureA
FeatureB
FeatureC
StateA
StateB
StateC
App
import {Component, OnInit} from '@angular/core';
import {Hero} from '../hero';
import {HeroService} from '../hero.service';
@Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: [ './dashboard.component.css' ]
})
export class DashboardComponent implements OnInit {
heroes: Hero[] = [];
constructor(private heroService: HeroService) { }
ngOnInit(): void {
this.getHeroes();
}
getHeroes(): void {
this.heroService.getHeroes()
.subscribe(heroes => this.heroes = heroes.slice(1, 5));
}
}
<div>
<label for="new-hero">Hero name: </label>
<input id="new-hero" #heroName />
<!-- (click) passes input value to add() and then clears the input -->
<button type="button" class="add-button" (click)="add(heroName.value); heroName.value=''">
Add hero
</button>
</div>
<h2>Top Heroes</h2>
<div class="heroes-menu">
<a *ngFor="let hero of heroes"
routerLink="/detail/{{hero.id}}">
{{hero.name}}
</a>
</div>
<app-hero-search></app-hero-search>
export class DashboardComponent implements OnInit {
heroes: Hero[] = [];
constructor(private heroService: HeroService) { }
ngOnInit(): void {
this.getHeroes();
}
getHeroes(): void {
this.heroService.getHeroes()
.subscribe(heroes => this.heroes = heroes.slice(1, 5));
}
add(name: string) {
name = name.trim();
if (!name) { return; }
this.heroService.addHero({ name } as Hero)
.subscribe(hero => {
this.heroes.push(hero);
});
}
}
export class DashboardComponent implements OnInit {
heroes: Hero[] = [];
constructor(private heroService: HeroService) { }
ngOnInit(): void {
this.getHeroes();
}
getHeroes(): void {
this.heroService.getHeroes()
.subscribe(heroes => this.heroes = heroes.slice(1, 5));
}
add(name: string) {
name = name.trim();
if (!name) { return; }
this.heroService.addHero({ name } as Hero)
.subscribe(hero => {
this.heroes.push(hero);
});
}
}
export class DashboardComponent implements OnInit {
heroes: Hero[] = [];
constructor(private heroService: HeroService) { }
ngOnInit(): void {
this.getHeroes();
}
getHeroes(): void {
this.heroService.getHeroes()
.subscribe(heroes => this.heroes = heroes.slice(1, 5));
}
add(name: string) {
name = name.trim();
if (!name) { return; }
this.heroService.addHero({ name } as Hero)
.subscribe(hero => {
this.heroes.push(hero);
});
}
}
export class DashboardComponent implements OnInit {
heroes: Hero[] = [];
constructor(private heroService: HeroService) { }
ngOnInit(): void {
this.getHeroes();
}
getHeroes(): void {
this.heroService.getHeroes()
.subscribe(heroes => this.heroes = heroes.slice(1, 5));
}
add(name: string) {
name = name.trim();
if (!name) { return; }
this.heroService.addHero({ name } as Hero)
.subscribe(hero => {
this.heroes.push(hero);
});
}
}
export class SomeStateService {
private readonly $data = new BehaviorSubject<SomeData[]>([]);
readonly data$ = this.$data.asObservable();
private readonly $loading = new BehaviorSubject<boolean>(false);
readonly loading$ = this.$loading.asObservable();
constructor(private readonly someService: SomeService) {}
getData() {
this.$loading.next(true);
this.someService.getData().subscribe({
next: data => {
this.$data.next(data);
this.$loading.next(false);
},
error: error => {
console.log(error);
this.$loading.next(false);
},
})
}
addData(item) {
this.$loading.next(true);
this.someService.addData(item).subscribe({
next: addedItem => {
this.$data.next([...this.$data.value, addedItem]);
this.$loading.next(false);
},
error: error => {
console.log(error);
this.$loading.next(false);
},
})
}
filter(query) {
this.$data.next(this.$data.value.filter(...));
}
}
Read
Write
Side-effect
select
updater
effect
@ngrx/store
createSelector
createReducer
createReducer
createEffect
Demo
Demo
no subscriptions
race-conditions built-in
easy to graduate to a global store if needed
easier to test too