דלגו לתוכן

ngrx/store@ - זרימת נתונים

פורסם בתאריך 19 בנובמבר 2023

ננסה לשמור על פשטות ולהתמקד בליבת @ngrx/store ובזרימת הנתונים הבסיסית באפליקציה של Angular עם NGRX.
מטרתנו בשיעור זה היא להבין 3 אלמנטים מרכזיים מ-@ngrx/store:

  • Store
  • Action
  • Reducer

עם אלמנטים אלו ועם הרכיבים שלנו באנגולר, יש זרימת נתונים פשוטה שמתוארת בתרשים הבא:

@ngrx/store - data flow

הדיאגרמה אינה מתארת את הדיאגרמה המלאה של NGRX, חשוב לראות אותה כמנוע של הרכב, לדיאגרמה זו נוסיף בהדרגה חלקים נוספים עד שנבין את הרכב כולו, אבל כדאי להתחיל מגרסה פשוטה ולבנות את הדרך משם.

Store

נבחן את הדיאגרמה ונתחיל עם ה-Store. ה - Store הוא Service שמסופק על ידי @ngrx/store.
כאשר אנחנו מתקינים את @ngrx/store אנחנו יכולים להזריק את ה-Store כ - Service באמצעות DI של Angular.

Terminal window
npx ng add @ngrx/store@latest
some.component.ts
import {Component} from '@angular/core'
import {Store} from '@ngrx/store'
@Component({
selector: 'some-component',
...
})
export class SomeComponent {
constructor(private store: Store) {}
}

בדוגמא זו ה- Component מבקש את ה- Store Service.

ישנו רק instance אחד של ה- Store בכל האפליקציה שלנו. ה - Store מחזיק את ה - State של האפליקציה, והשימוש העיקרי ב- Store הוא:

  • מזריקים את ה- Store לקריאת ה - State
  • מזריקים את ה- Store כדי לשנות את ה - State

קריאת ה - State

Component של אנגולר שקורא את ה - State מיוצג בחלק זה של הדיאגרמה:

@ngrx/store - data flow - reading the state

ניתן לקרוא את ה - State על ידי הזרקת ה - Store ושימוש בפעולת ה - select.

import { Component, ChangeDetectionStrategy } from "@angular/core";
import { Store } from "@ngrx/store";
import { State } from "./state";

@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: "app-root",
template: `<h1>Reading counter from state: {{ counter$ | async }}</h1>`
})
export class AppComponent {
counter$ = this._store.select((state) => state.counter);
constructor(private _store: Store<State>){}
}

שימו לב שכאשר אתם משתמשים ב - store.select כדי לקרוא נתונים מה - State, אתם מקבלים Observable של הנתונים, ולכן עליכם להשתמש ב - async pipe ב -

שינוי ה - State

אחרי שהזרקנו את ה - Store וקראנו את ה - State, נוכל לשנות את ה - State על ידי שימוש ב - store.dispatch. החלק הזה של הזרימה קצת מורכב, אז נפרק אותו לפרטים.

Trigger state change

שינוי יתחיל ממשהו שמפעיל את תהליך השינוי (בדוגמא של הדיאגרמה שלמעלה זה לחיצת כפתור).

דברים פופולריים שיפעילו את תהליך השינוי הם:

  • פעולות משתמש (כמו לחיצת כפתור)
  • בקשות או תגובות מהשרת
  • אירועי טיימר
  • אפקטים שמהווים שינוי שנובע משינוי אחר (על זה נדון בשיעור על אפקטים)

נשמור על פשטות בדוגמא זו ונשתמש בלחיצת כפתור כדי להפעיל את תהליך השינוי. תצפו בדוגמא הבאה שמגדילה מונה בכל לחיצת כפתור.

import { Component, ChangeDetectionStrategy } from "@angular/core";
import { Store } from "@ngrx/store";
import { State } from "./state";

@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: "app-root",
template: `<button (click)="increment()">Increment: {{ counter$ | async }}</button>`
})
export class AppComponent {
counter$ = this._store.select((state) => state.counter);
constructor(private _store: Store<State>){}

increment() {
	this._store.dispatch({ type: 'INCREMENT' });
}
}

אנחנו משתמשים ב - this._store.dispatch({ type: 'INCREMENT' }) כדי לשלוח Action, יש שיעור מלא על Action בקישור כאן, אבל כרגע נראה על Action כ - Object פשוט שמתאר מה קרה עם זיהוי (במקרה שלנו הזיהוי הוא: type: 'INCREMENT') ונתונים אופציונליים payload אם האירוע צריך לשלוח מידע נוסף.

store.dispatch

כאשר נרצה להתחיל שינוי ב - State, אנחנו מזריקים את ה - Store וקוראים ל - store.dispatch(action) ושולחים מידע על האירוע שקרה.

Reducer

ה- Reducer מקבל את ה - State הנוכחי ואת ה - Action שקרה ומחזיר את ה - State החדש. נסתכל על Reducer פשוט:

export function counterReducer(state, action) {
if (action.type === 'INCREMENT') {
	return state + 1;
} else {
	return 0;
}
}

ה- Reducer הוא פונקציה שמקבלת את ה - State הנוכחי ואת ה - Action שקרה ומחזירה את ה - State החדש.

reducer

וזהו החלק האחרון בזרימת הנתונים של NGRX.

סיכום

בשיעור זה למדנו על זרימת הנתונים ב-NGRX שמורכבת מהחלקים הבאים:

  1. Store - המחזיק את ה - State של האפליקציה
  2. Component יכול לקרוא את ה - State על ידי הזרקת ה - Store ושימוש ב - store.select
  3. Component יכול לשנות את ה - State על ידי שימוש ב - store.dispatch(Action)
  4. ה- store.dispatch(Action) מקבל Action שמתאר מה קרה.
  5. ה- Reducer מקבל את ה - State הנוכחי ואת ה - Action שקרה ומחזיר את ה - State החדש.
  6. ה- Store משנה את ה - State לפי ה - State החדש שהוחזר על ידי ה - Reducer
  7. ה - Component יקבל את ה - State החדש וירנדר את ה- template עם המידע החדש.