iT邦幫忙

2025 iThome 鐵人賽

DAY 16
0
Modern Web

Angular 進階實務 30天系列 第 16

Day 16:狀態管理 - 資料儲存(Data Storage) → 資料在哪裡?

  • 分享至 

  • xImage
  •  

前言

狀態管理我預計拆成三個面向來分享:

  1. 資料儲存 (Data Storage) – 資料應該放在哪裡?它的生命週期是什麼?
  2. 資料流控制 (Data Flow Control) – 資料應該如何流動?父子元件怎麼傳?跨元件怎麼共享?
  3. 狀態變更 (State Changes) – 資料應該如何被修改?用戶操作、API 回應、非同步事件又要怎麼處理?

這三者共同構成了應用程式的「狀態管理系統」:

  • 資料儲存 決定「狀態存在的地方」。
  • 資料流控制 決定「狀態如何流動」。
  • 狀態變更 決定「狀態如何被修改」。

讓我們先回答 Angular 的狀態管理中的第一個問題:

👉 「資料應該存在哪裡?」

不同的儲存方式,代表了不同的生命週期、共享範圍,以及不同的使用情境。

有些資料只需要在單一頁面存在,有些必須跨元件共享,有些甚至需要在使用者關閉分頁後仍然保留。

本篇文章將依照三大類來介紹常見的資料儲存方式:

  1. 本地儲存 (Local in App) → 存在應用程式記憶體內,重新整理會消失。
  2. 狀態保存 (RouteReuseStrategy) → 保存整個元件實例與 UI 狀態。
  3. 持久化儲存 (Persistent Storage) → 使用者重新整理或關閉分頁後仍能存在。

一、本地儲存 (Local in App)

1. 組件屬性 (Component Properties)

export class ProfileComponent {
  userName = 'Alice';
}

  • 優點:最直覺,適合小範圍狀態(像 modal 是否開啟)。
  • 缺點:無法跨元件共享,重新整理後消失。
  • 適用場景:單頁表單、局部 UI 狀態。

2. Service 儲存 (Service Variables)

@Injectable({ providedIn: 'root' })
export class UserService {
  currentUser?: User;
}

  • 優點:可跨元件共享,搭配 Angular DI 很方便。
  • 缺點:容易變成「全域變數垃圾桶」,若沒有結構化規劃會失控。
  • 適用場景:登入使用者資訊、跨頁共用的查詢條件。

💡 補充:Service 可以是

  • 模組級 (Scoped) → 每個 lazy module 各自有一份實例。
  • 全域級 (Singleton) → 全應用共用同一份實例。

3. RxJS Subject / BehaviorSubject

@Injectable({ providedIn: 'root' })
export class NotificationService {
  private message$ = new BehaviorSubject<string>('Hello');

  get messages() {
    return this.message$.asObservable();
  }

  pushMessage(msg: string) {
    this.message$.next(msg);
  }
}

  • 優點:支援訂閱,適合跨元件通訊。
  • 缺點:需要 RxJS 基礎,過度使用會讓邏輯難追蹤。
  • 適用場景:通知中心、購物車數量更新。

二、狀態保存 (RouteReuseStrategy)

大多數儲存方式都只保存「資料」,但在某些情境下,使用者需要的是 整個頁面狀態(例如輸入中的表單、滾動位置、已展開的 Tab)。

這時候可以用 RouteReuseStrategy 來快取整個元件實例。

程式碼範例

export class CustomReuseStrategy implements RouteReuseStrategy {
  private cache = new Map<string, DetachedRouteHandle>();

  shouldDetach(route: ActivatedRouteSnapshot): boolean {
    return route.routeConfig?.path === 'order';
  }

  store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
    this.cache.set(route.routeConfig!.path!, handle);
  }

  shouldAttach(route: ActivatedRouteSnapshot): boolean {
    return this.cache.has(route.routeConfig!.path!);
  }

  retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null {
    return this.cache.get(route.routeConfig!.path!) || null;
  }

  shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
    return future.routeConfig === curr.routeConfig;
  }
}


RouteReuseStrategy 的儲存特性

特性 Route Reuse Strategy
儲存位置 瀏覽器記憶體
儲存內容 元件實例 + DOM + 狀態
生命週期 路由存在期間
容量限制 受記憶體限制
存取速度 非常快(直接記憶體存取)
適用場景 頻繁切換的頁面,保持使用者體驗

Service 管理 vs RouteReuseStrategy

層面 手動 Service 管理 Route Reuse Strategy
程式碼量 大量 boilerplate 幾乎零額外程式碼
維護成本 每新增狀態都要改 Service 完全不用改
涵蓋範圍 只有手動指定的狀態 所有狀態 + DOM 狀態
出錯機率 容易忘記同步某些狀態 零出錯(自動處理)
效能 需要手動序列化 / 反序列化 直接記憶體存取

小結

  • RouteReuseStrategy 不只是保存「資料」,而是把整個 元件快照 記住,包括表單輸入、滾動位置、UI 狀態。
  • 相比手動用 Service 管理,RouteReuseStrategy 幾乎零樣板程式碼,開發體驗更佳。
  • 但因為依賴記憶體,它不適合用來保存大量資料,而是專注於「提升使用者切換體驗」。

三、持久化儲存 (Persistent Storage)

1. localStorage / sessionStorage

localStorage.setItem('theme', 'dark');
sessionStorage.setItem('step', '2');

  • localStorage → 永久保存(除非清除)。
  • sessionStorage → 僅在當前分頁存活。
  • 適用場景:偏好設定、一次性流程。

2. Cookie

  • 特點:可自訂過期時間,常用於登入狀態。
  • 缺點:容量小(4KB),每次請求自動帶上,可能影響效能。
  • 適用場景:登入憑證(例如 JWT Token)。

3. history.state

history.pushState({ page: 1, filter: 'active' }, '');

  • 特點:可存任意序列化資料(物件、快照)。
  • 生命週期:隨著瀏覽紀錄存活,前進/返回時可還原。
  • 適用場景:分頁瀏覽、查詢條件的回溯。

4. IndexedDB / Service Worker

進階持久化技術,可支援大量資料與離線應用,但 不在本系列範圍


對比總表

方式 儲存內容 生命週期
localStorage 純資料 (字串化 JSON) 永久保存
Service (Scoped/Global) 純資料(存在於記憶體) 應用期間(重新整理即消失)
RxJS Subject 可訂閱資料流 應用期間
Route Reuse 元件實例 + DOM + UI 狀態 路由存在期間(直到回收)
sessionStorage 純資料 (字串化 JSON) 分頁存活(關閉即消失)
Cookie 純資料(伺服器/前端皆可存取) 可自訂過期時間
history.state 任意序列化快照 瀏覽紀錄存活期間

結語

本篇我們回答了「資料應該存在哪裡」這個問題:

  • 小範圍 → Component Property。
  • 跨元件共享 → Service 或 RxJS。
  • 保持 UI 狀態 → RouteReuseStrategy。
  • 持久化需求 → localStorage、Cookie、history.state。

👉 下一篇 Day 17:資料流控制 (Data Flow Control),將探討「資料怎麼流動」。


上一篇
Day 15:用 Angular RouteReuseStrategy 打造可切換分頁的功能
下一篇
Day 17:狀態管理 - 資料流控制 (Data Flow Control) → 資料怎麼流動?
系列文
Angular 進階實務 30天18
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言