Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
NgRx Component Store
Search
Rainer Hahnekamp
July 20, 2022
Technology
1
91
NgRx Component Store
Slides for my talk on NgRx Component Store
Rainer Hahnekamp
July 20, 2022
Tweet
Share
More Decks by Rainer Hahnekamp
See All by Rainer Hahnekamp
Evolving Architecture
rainerhahnekamp
3
300
Microfrontends: Necessities - Implementations - Challenges
rainerhahnekamp
0
140
Zoneless Testing
rainerhahnekamp
0
160
Towards Modern Change Detection
rainerhahnekamp
0
16
Testing in 2024: A "dynamic" Situation
rainerhahnekamp
0
120
End of Barrel Files: New Modularization Techniques with Sheriff
rainerhahnekamp
0
440
ESLint: Low Hanging Fruits
rainerhahnekamp
0
410
Refactoring in Angular via Metrics, Modularity & Testing
rainerhahnekamp
0
390
Testing in 2024
rainerhahnekamp
0
340
Other Decks in Technology
See All in Technology
依存関係があるコンポーネントは Barrel ファイルでまとめよう
azukiazusa1
3
530
AndroidXR 開発ツールごとの できることできないこと
donabe3
0
110
サーバーレスアーキテクチャと生成AIの融合 / Serverless Meets Generative AI
_kensh
12
3k
Building Products in the LLM Era
ymatsuwitter
10
4.4k
AndroidデバイスにFTPサーバを建立する
e10dokup
0
240
Nekko Cloud、 これまでとこれから ~学生サークルが作る、 小さなクラウド
logica0419
2
730
Moved to https://speakerdeck.com/toshihue/presales-engineer-career-bridging-tech-biz-ja
toshihue
2
550
MC906491 を見据えた Microsoft Entra Connect アップグレード対応
tamaiyutaro
1
480
Datadog APM におけるトレース収集の流れ及び Retention Filters のはなし / datadog-apm-trace-retention-filters
k6s4i53rx
0
320
転生CISOサバイバル・ガイド / CISO Career Transition Survival Guide
kanny
2
390
家電アプリ共通PF "Linova" のAPI利用とPostman活用事例ご紹介
yukiogawa
0
130
関東Kaggler会LT: 人狼コンペとLLM量子化について
nejumi
3
460
Featured
See All Featured
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
44
7k
Producing Creativity
orderedlist
PRO
343
39k
The Power of CSS Pseudo Elements
geoffreycrofte
75
5.5k
How to train your dragon (web standard)
notwaldorf
90
5.8k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
175
51k
The World Runs on Bad Software
bkeepers
PRO
67
11k
The Language of Interfaces
destraynor
156
24k
Fontdeck: Realign not Redesign
paulrobertlloyd
82
5.4k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
193
16k
The Pragmatic Product Professional
lauravandoore
32
6.4k
Optimising Largest Contentful Paint
csswizardry
34
3.1k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
49
2.3k
Transcript
NgRx Component Store NgRx Component Store Rainer Hahnekamp 20.7.2022
About Me... • Rainer Hahnekamp ANGULARarchitects.io • Trainings and Consulting
@RainerHahnekamp Professional NgRx https://www.ng-news.com https://www.youtube.com /c/RainerHahnekamp
Agenda • NgRx Family • Theory • Selectors • Actions
• Effects • Miscellaneous
NgRx Family Store Effects Entity Data Router Store Store Devtools
Schematics ESLint Plugin Component Store Component
Main facts • (Little) sibling to @ngrx/store • Local /
component state management • State vanishes with component (by default) • Push-based • All logic included in single service
Use cases • Complicated, local state logic • Multiple instances
of same components • Different static logic (Decoupling, Shared) • ~Simplified, global state
API ComponentStore SideEffects Read Write select(): Observable patchState() setState() updater()
// like reducer effect()
Defining the state export interface HolidaysState { holidays: Holiday[]; favouriteIds:
number[]; } @Injectable() export class HolidaysStore extends ComponentStore<HolidaysState> { constructor(private httpClient: HttpClient, private config: Configuration) { super({ holidays: [], favouriteIds: [] }); } }
Selectors export interface HolidaysState { holidays: Holiday[]; favouriteIds: number[]; }
@Injectable() export class HolidaysStore extends ComponentStore<HolidaysState> { constructor(private httpClient: HttpClient, private config: Configuration) { super({ holidays: [], favouriteIds: [] }); } readonly holidays$ = this.select(({ holidays, favouriteIds }) => holidays.map((holiday) => ({ ...holiday, isFavourite: favouriteIds.includes(holiday.id), })) ); }
Using the ComponentStore @Component({ templateUrl: './holidays.component.html', standalone: true, imports: [...],
providers: [HolidaysStore], }) export class HolidaysComponent { holidays$ = this.holidaysStore.holidays$; constructor(private holidaysStore: HolidaysStore) { } }
Actions @Injectable() export class HolidaysStore extends ComponentStore<HolidaysState> { // ...
addFavourite(holidayId: number) { this.patchState((state) => ({ favouriteIds: [...state.favouriteIds, holidayId], })); } removeFavourite(holidayId: number) { this.patchState((state) => ({ favouriteIds: state.favouriteIds.filter((id) => id !== holidayId), })); } }
Using the ComponentStore @Component({ templateUrl: './holidays.component.html', standalone: true, imports: [...],
providers: [HolidaysStore], }) export class HolidaysComponent { holidays$ = this.holidaysStore.holidays$; constructor(private holidaysStore: HolidaysStore) { } addFavourite(id: number) { this.holidaysStore.addFavourite(id); } removeFavourite(id: number) { this.holidaysStore.removeFavourite(id); } }
Effects @Injectable() export class HolidaysStore extends ComponentStore<HolidaysState> { // ...
readonly load = this.effect((i$: Observable<void>) => { return i$.pipe( switchMap(() => this.httpClient.get<Holiday[]>(this.#baseUrl).pipe( tapResponse((holidays) => { const finalHolidays = holidays.map((holiday) => ({ ...holiday, imageUrl: `${this.config.baseUrl}${holiday.imageUrl}`, })); this.#setHolidays(finalHolidays); }, console.error) ) ) ); }); #setHolidays = (holidays: Holiday[]) => this.patchState({ holidays }); }
Using the ComponentStore @Component({ templateUrl: './holidays.component.html', standalone: true, imports: [...],
providers: [HolidaysStore], }) export class HolidaysComponent { holidays$ = this.holidaysStore.holidays$; constructor(private holidaysStore: HolidaysStore) { this.holidaysStore.load(); } addFavourite(id: number) { this.holidaysStore.addFavourite(id); } removeFavourite(id: number) { this.holidaysStore.removeFavourite(id); } }
Comparison to store • Same reactive behaviour • No devtools
• Scalability issues • Simpler • Nice goodies ◦ patchState ◦ Debounced selectors
Also keep in mind • Disposing of resources is built-in
• Combination with @ngrx/store possible • Can also manage global state ◦ via {providedIn: 'root'}
When to use? • Instead of services based on BehaviorSubject
• Non-global state • Early phases of application development
Alternatives Elf @rx-angular/state
Summary • Simple State Management • Reactive Behaviour • Easy
to upgrade to NgRx Store later
Further Reading/Watching • Original Design Document ◦ https://hackmd.io/zLKrFIadTMS2T6zCYGyHew?view • Official
Documentation ◦ https://ngrx.io/guide/component-store • Alex Okrushko on Component Store ◦ https://www.youtube.com/watch?v=v5WSUE1_YHM