接下來我們將會先講講 store究竟是什麼
誠如我之前所說,假如我們只是要進行一頁式或不涉及暫存在我們自己的系統中的話,Store其實是不需要的,畢竟我也可以透過component的input將我的資料暫存到property帶到下一層嘛
但這樣子的資料在功能逐漸複雜化之後就會變成管理上的一大難題,君不見道路圓環無限的增加連接支道後那叫做印度的廣場,路面上滿是自由來去的人、車、牛,無限接下去只會讓我們追蹤特定車子的動向變得複雜
這時候我們就需要一個覆蓋於整個系統的脈絡來進行系統全域的資料管理,就像是一個集中式的貨物中心,透過高來高去的管道直接連結(subscribe)中央資料儲存區(Store)
"Store" 通常指的是一個集中式的數據管理系統或存儲庫,用於存儲和管理應用程序的數據和狀態。每個框架現行其實都有因應這方面的需求發展出了相關的生態系函式庫,如Redux(用於React),Vuex(用於Vue.js)或NgRx(用於Angular),這些函式庫提供了一種以可預測和有組織的方式管理和訪問數據的機制。
Store
包含應用程序的數據,包括用戶檔案、設置和與應用程序功能相關的其他信息,但我不太可能每個資料的新舊資料都放進去,要記住,value的不同在記憶體之中它就是不一樣的內容了,所以理論上來說我們所取得到的資料都會是最新的,那怕在操作情境上是還原了上一個步驟的值,但依照其概念是我們在這一個管道上放了一個最新的值,只不過這個值正好跟之前一樣
彈珠圖的說法已經很多人說過了,我絕對沒其他人說的好XD 但因為我很喜歡吃速食所以讓我用得來速來解釋
這是一家客人(資料)非常之懶散的某速食店,只有被後面的人叭了之後才會離開取餐餐口,每一次的資料更新都是後車叭前車之後,前車開走了,後面那台車往前開到取餐餐口來進行操作情境的交互互動,而新的取餐需求(新的資料)會影響到中央廚房準備餐點,所有關注這個取餐餐口的中央廚房料理小組(各個訂閱subscirbe)可能會有漢堡小組(component_subscribe_1)、薯條小組(component_subscribe_2)...
假如資料有一樣的狀況,那我們要做的也是按照這個資料再去觸發相同的備餐程序,頂多就是心裡唸叨兩句這個開紅色雪福蘭的人好眼熟而已
我們關注的只會是眼前當下這個窗口所看到的資料(客人),我們不會管以前的資料去了哪裡
使用 Store
的一個關鍵好處是,它實現了數據的可預測和單向流動。這使得更容易理解數據的變化,並有助於防止與不一致的狀態更新相關的錯誤。它通常可以從應用程序中的各種組件中訪問,從而使其成為檢索數據和更新的中心樞。
而我們在app.config.ts
中就是進行store的存放登記
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { routes } from './core/routes/app.routes';
import { provideStore } from '@ngrx/store';
import { reducer } from './core/store/reducers';
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
provideStore({
layout: reducer.layout,
}),
],
};
說完了Store之後我們來說說要怎麼從中取得這個資料以及資料流
我很喜歡資料流的這個概念,他某種程度其實說明了在系統層級上資料最好是單向,而且大多都是由上而下
假如我們要實作取得資料的這件事我們可以建立一個資料流-或者說像是安裝好水管,而將資料取出來就是利用水龍頭Subscribe
,而水管則是主要有兩種類型Observable
、Subject
,Observable比較像是一個必須依賴於subscribe
開啟水龍頭之後,讓其他水桶(參數)來接這個水(資料)來給自己喝(功能實作),他本身只是一個資料流,沒辦法有一個真實的值
Subject
比較不一樣,他可以直接取到值來進行使用,換言之,他就像是即飲水龍頭水管,我可以透過subscribe
取用資料,也可以直接對著水管直接喝,甚至可以由我們自己手動next(value)
進行下一個state的更新
import { Component, inject } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Observable, Subject, takeUntil } from 'rxjs';
import { Store } from '@ngrx/store';
import * as fromPagesReducers from '../../../core/store/reducers';
@Component({
standalone: true,
imports: [CommonModule],
templateUrl: './shopping-home.component.html',
styleUrls: ['./shopping-home.component.scss'],
})
export class ShoppingHomeComponent {
private store = inject(Store<fromPagesReducers.State>);
private destroy$ = new Subject<void>();
loading$: Observable<boolean> = this.store
.select((x) => x.layout.Loading)
.pipe(takeUntil(this.destroy$));
}
也因為這個特性,Subject
更加地適合用在主動控制的數據流上,例如當前component
中的元件資料狀態處理,mouse event,或是當作中斷API Request制動裝置,而Observable
則是更加地應用在被動形式的資料流,如系統層級的資料當前state
,舉凡loading、userInfo、isLogin等都是系統層級的資料狀態,也因為API的形式其實是更加被動接受資料,所以也較適合用Observable
最後的最後state就如同字面的意思上,就是當前資料的狀態而已XDD相當於我在之前所舉例的麥當勞窗口,每個取餐單都是一個新的資料狀態
明天我們將會說說我要怎麼更新以及取用資料狀態~也就是 Action->Effect->Reducer的流程