首頁 >web前端 >js教程 >NGRX 的訊號儲存 - 主要概念細分

NGRX 的訊號儲存 - 主要概念細分

WBOY
WBOY原創
2024-07-23 15:00:551228瀏覽

The Signal Store from NGRX - breakdown of the main concepts

特徵

  • 基於訊號
  • 函數式與宣告式
  • 用於本地或全域狀態管理
  • 可透過自訂功能進行擴充

與 NGRX 全球商店相比如何?

  • 更輕量級簡化的API
  • 不必太擔心資料流
  • 似乎更難誤用,例如重用動作
  • 更容易擴充

NGRX Signal Store 的創建者,Marko Stanimirovic 在此描述了 NgRx SignalStore:深入了解 Angular 中基於訊號的狀態管理

基於類別的狀態管理限制:

  • 型別:不可能定義強型別的動態類別屬性或方法
  • Tree-shaking:未使用的類別方法不會從最終套件中刪除
  • 可擴充性:不支援多重繼承。
  • 模組化:可以將選擇器、更新器和效果分割為不同的類,但不能開箱即用

讓我們透過程式碼範例來探索商店的 API。我們將使用一個包含產品清單和過濾功能的項目。

建立 SignalStore

  • signalStore 函數傳回一個適合注入並在需要使用時提供的可注入服務。
import { signalStore } from "@ngrx/signals";

export const ProductStore = signalStore( … );

提供狀態withState

與迄今為止的任何 NGRX Store 一樣,可以使用函數 withState 來提供初始狀態,該函數接受物件文字、記錄或工廠函數(用於建立動態初始狀態)作為輸入。

import { signalStore, withState } from "@ngrx/signals";

const initialProductState: ProductState = { products: [] };

export const ProductStore = signalStore(
 withState(initialProductState);
);

計算狀態 withCompated

  • 建構在計算函數之上,從儲存建立派生狀態(計算狀態)
import { signalStore, withComputed, withState } from "@ngrx/signals";

export const ProductStore = signalStore(
 withState(initialProductState),
 withComputed(({products}) => ({
   averagePrice: computed(() => {
     const total = products().reduce((acc, p) => acc + p.price, 0);
     return total / products().length;
   })
 })),

執行操作 withMethods

  • 這是定義商店經營的地方
  • 這些可以是更新儲存或根據其當前狀態執行某些操作的方法
import { signalStore, withComputed, withState, withMethods } from "@ngrx/signals";

export const ProductStore = signalStore(
 withState(initialProductState),
 withComputed(({products}) => ({
   averagePrice: computed(() => {
     const total = products().reduce((acc, p) => acc + p.price, 0);
     return total / products().length;
   })
 })),


 // CRUD operations
 withMethods((store,
   productService = inject(ProductService),
 ) => ({
   loadProducts: () => {
     const products = toSignal(productService.loadProducts())
     patchState(store, { products: products() })
   },
   addProduct: (product: Product) => {
     patchState(store, { products: [...store.products(), product] });
   },
   // ...
 })),

withMethods & withCompulated 取得工廠函數並傳回可以透過使用存取的方法和計算訊號的字典商店。它們還在註入上下文中運行,這使得可以將依賴項注入到它們中。

掛鉤 withHooks

  • store 的生命週期方法,目前有 onInitonDestroy 方法
import { withHooks } from "@ngrx/signals"; 

export const ProductStore = signalStore(
 withHooks((store) => ({
   onInit() {
     // Load products when the store is initialized
     store.loadProducts();
   },
 })),
);

使用實體管理集合

  • 當必須管理「產品、使用者、客戶等」等資料時使用它,其中該功能需要 CRUD 操作
  • 它提供了一組API來管理集合,例如:addEntitysetEntityremoteEntity
export const ProductStoreWithEntities = signalStore(
 withEntities<Product>(),


 // CRUD operations
 withMethods((store,
   productService = inject(ProductService),
 ) => ({
   loadProducts: () => {
     const products = toSignal(productService.loadProducts())();
     patchState(store, setAllEntities(products || []));
   },
   updateProduct: (product: Product) => {
     productService.updateProduct(product);
     patchState(store, setEntity(product));
   },

 })),

可以新增以「with」開頭的多個功能,但它們只能存取先前定義的內容。

使用 signalStoreFeature 建立自訂功能

signalStoreFeature - 用於擴展商店的功能。

對於大型企業應用程式來說,商店可能會變得複雜且難以管理。在為專案編寫功能和元件時,拆分得越好、越細,就越容易管理、維護程式碼和為其編寫測試。

但是,考慮到 SignalStore 提供的 API,除非相應地拆分程式碼,否則儲存可能會變得難以管理。 signalStoreFeature 適合將功能(或組件)的特定功能提取到獨立的可測試函數中,該函數可能(並且理想情況下)可以在其他商店中重複使用。

export const ProductStore = signalStore(
 // previous defined state and methods

 // Externalizing filtering options
 withFilteringOptions(),
);


export function withFilteringOptions() {
 return signalStoreFeature(
  // Filtering operations
 withMethods(() => ({
   getProductsBetweenPriceRange: (lowPrice: number, highPrice: number, products: Array<Product>, ) => {
     return products.filter(p => p.price >= lowPrice && p.price <= highPrice);
   },


   getProductsByCategory: (category: string, products: Array<Product>) => {
     return products.filter(p => p.category === category);
   },
 })),
 );
}

現在是 signalStoreFeature 的範例,它展示了跨多個商店重複使用 signalStoreFeature 的可能性。

從「@ngrx/signals」導入{ patchState, signalStoreFeature, withMethods };

export function withCrudOperations() {
 return signalStoreFeature(
   withMethods((store) => ({
     load: (crudService: CrudOperations) => crudService.load(),
     update: (crudableObject: CRUD, crudService: CrudOperations) => {
       crudService.update(crudableObject);
       patchState(store, setEntity(crudableObject));
     },
   }),
 ));
}

export interface CrudOperations {
 load(): void;
 update(crudableObject: CRUD): void;
}

// Product & Customer services must extend the same interface.

export class ProductService implements CrudOperations {
 load(): void {
   console.log('load products');
 }
 update(): void {
   console.log('update products');
 }
}

export class CustomerService implements CrudOperations {
 load(): void {
   console.log('load customers');
 }
 update(): void {
   console.log('update customers');
 }
}

// and now let’s add this feature in our stores

export const ProductStore = signalStore(
 withCrudOperations(),
);


export const CustomerStore = signalStore(
 withCrudOperations(),
);

NGRX 工具包實用程式包

由於易於擴展,已經有一個名為 ngrx-toolkit 的實用程式包,旨在為訊號儲存添加有用的工具。

注入SignalStore

{providedIn: ‘root’} 或在元件、服務、指令等的提供者陣列中

深度訊號

  • 巢狀狀態屬性讀取為訊號,隨選延遲產生

補丁狀態

  • setupdate(訊號 API)的替代 API,用於更新儲存狀態,只需要提供我們想要更改的值

接收方法

  • 幫助將 RxJS 與 SignalStore 或 signalState 一起使用的實用方法

使用 SignalState 進行更輕的替代方案

  • SignalState 提供了一種以簡潔和簡約的方式管理基於訊號的狀態的替代方法。

結論性想法

對於大型應用程式來說,它的可靠性還有待證明,尤其是作為全球商店應用程式時。

目前我認為它是對預設 Signal API 的一個很好的補充,使其成為管理的一個不錯的選擇:

  • 組件層級狀態
  • 基於特徵的狀態

其他資源:

https://www.stefanos-lignos.dev/posts/ngrx-signals-store
https://www.angulararchitects.io/blog/the-new-ngrx-signal-store-for-angular-2-1-flavors/(關於該主題的 4 篇文章)
https://ngrx.io/guide/signals

以上是NGRX 的訊號儲存 - 主要概念細分的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn