Chuyển đến nội dung chính

レッスン 14: MFE 間の状態管理とコミュニケーション

Micro Frontend の状態管理パターン。カスタム イベント、イベント バス、URL ベースの状態、ブラウザ ストレージ。グローバル状態の共有は避けてください。 React Context、CustomEvent を使用した実践的なパターン。

🏗️ アーキテクチャ — レッスン 14 レッスン 14: MFE 間の状態管理と コミュニケーション

マイクロサービスとマイクロ フロントエンドのシステム設計 — 基本から運用まで

パート 5: 実用的なマイクロ フロントエンドの構築

xdev.asia

はじめに

クロス MFE 通信は、Micro Frontend の最大の課題です。各 MFE は、共有メモリを使用せずに、独自のランタイムで実行されます。この記事では、安全な通信パターンを紹介します。


1. 黄金律

MFE は 疎結合である必要があります。共有状態ではなく、コントラクトを介して通信します。

❌ Shared Global State:
window.globalStore = { cart: { items: [...] } }
→ Coupling nightmare, race conditions

✅ Event-based Communication:
MFE A publishes: "cart:item-added" { productId, qty }
MFE B subscribes: update cart badge
→ Loosely coupled, observable

2. コミュニケーションパターン

2.1 カスタム イベント (ブラウザネイティブ)

// Product MFE - Publish
window.dispatchEvent(new CustomEvent('cart:item-added', {
  detail: { productId: '123', name: 'Laptop', price: 999 }
}));

// Cart MFE - Subscribe
useEffect(() => {
  const handler = (e) => {
    setCartItems(prev => [...prev, e.detail]);
  };
  window.addEventListener('cart:item-added', handler);
  return () => window.removeEventListener('cart:item-added', handler);
}, []);

2.2 イベントバス (カスタム)

class EventBus {
  private handlers: Map<string, Set<Function>> = new Map();
  
  on<T>(event: string, handler: (payload: T) => void) {
    if (!this.handlers.has(event)) this.handlers.set(event, new Set());
    this.handlers.get(event)!.add(handler);
    return () => this.handlers.get(event)?.delete(handler);
  }
  
  emit<T>(event: string, payload: T) {
    this.handlers.get(event)?.forEach(h => h(payload));
  }
}

export const eventBus = new EventBus();

2.3 URL ベースの状態

/products?category=electronics&sort=price
→ URL là "shared state" tự nhiên: bookmarkable, shareable, no coupling

2.4 ブラウザのストレージ

// Shared preferences via localStorage
localStorage.setItem('user:preferences', JSON.stringify({
  currency: 'VND', language: 'vi', theme: 'dark'
}));

3. 国家所有規則

状態オーナーMFE がアクセスする方法
認証状態シェルコンテキスト / イベント
カートのアイテムカートMFEイベント
製品データ製品MFE共有されていません
ユーザー設定シェルローカルストレージ + イベント
URL パラメータシェル (ルーター)URL
UI テーマシェルCSS 変数

4. コントラクトファーストのコミュニケーション

// shared-types/events.ts
interface CartItemAddedEvent {
  type: 'cart:item-added';
  payload: { productId: string; name: string; price: number; quantity: number; };
}

interface CartUpdatedEvent {
  type: 'cart:updated';
  payload: { itemCount: number; total: number; };
}

5. ベストプラクティス

Mỗi MFE nên:
✅ Fetch dữ liệu riêng (own API calls)
✅ Manage state riêng (local state)
✅ Render independently
✅ Graceful degradation

Mỗi MFE KHÔNG nên:
❌ Import components từ MFE khác
❌ Access DOM của MFE khác
❌ Share runtime state qua window/global
❌ Assume MFE khác đã loaded

概要

  • カスタム イベント — シンプル、ブラウザネイティブ
  • イベント バス — 型付き、テスト可能
  • URL — ナビゲーション状態に最適
  • localStorage — ユーザー設定
  • ルール: 各 MFE は独自の状態を管理、イベントを介して通信します

次の記事: レッスン 15: デザイン システムと共有 UI — UX の一貫性を保つ