# useSubscription

`useSubscription` hook 提供了一種使用 WebSockets 從支付服務訂閱即時事件的簡單方法。它處理連線、訂閱和清理邏輯，讓您可以專注於應用程式如何對 `invoice.paid` 之類的事件做出反應。

這對於創建動態使用者體驗至關重要，其中 UI 需要即時回應後端事件，而無需使用者刷新頁面。

## 運作方式

此 hook 抽象化了管理 WebSocket 連線的複雜性。當元件使用 `useSubscription` 時，它會建立一個到中繼服務的持久連線。然後它會訂閱您提供的特定 `channel`。此 hook 會自動為您對頻道進行命名空間處理，建構一個格式為 `relay:<app-id>:<your-channel>` 的最終頻道名稱。

當後端服務向該頻道發布事件時，此 hook 的訂閱物件會發出該事件，您的元件可以監聽該事件。

<!-- DIAGRAM_IMAGE_START:architecture:16:9:1764919317 -->
![useSubscription](assets/diagram/use-subscription-diagram-0.zh-TW.jpg)
<!-- DIAGRAM_IMAGE_END -->

## 參數

此 hook 接受一個字串參數。

| 參數 | 類型 | 描述 | 必要 |
| :-------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------ | :------- |
| `channel` | `string` | 您想要監聽的事件流的唯一識別碼。**重要提示**：此字串不得包含 `/`、`.` 或 `:` 等分隔符。 | 是 |

## 返回值

此 hook 從底層的 `@arcblock/ws` 客戶端函式庫返回一個 `subscription` 物件。在建立連線期間，此物件最初可能為 `null`。

一旦連線成功，返回的物件提供了管理事件監聽器的方法：

- `subscription.on(eventName, handler)`：附加一個事件監聽器。
- `subscription.off(eventName, handler)`：移除一個事件監聽器。


## 範例用法

這是一個即時追蹤發票狀態的元件範例。當後端在發票的頻道上廣播 `invoice.paid` 事件時，元件的 UI 會自動更新。

```tsx Real-time Invoice Status Tracker icon=logos:react
import { useSubscription } from '@blocklet/payment-react';
import React, { useState, useEffect } from 'react';

/**
 * 一個顯示發票狀態的元件，並在收到 'invoice.paid' 事件時即時更新。
 */
function InvoiceStatusTracker({ invoiceId }) {
  const [status, setStatus] = useState('pending');
  // 訂閱此發票專用的頻道
  const subscription = useSubscription(invoiceId);

  useEffect(() => {
    // WebSocket 連線建立後，subscription 物件才會可用。
    if (subscription) {
      const handlePaymentSuccess = (eventData) => {
        console.log(`收到頻道 ${invoiceId} 的 'invoice.paid' 事件：`, eventData);
        // 根據事件更新元件的狀態
        setStatus('paid');
      };

      // 附加 'invoice.paid' 事件的監聽器
      subscription.on('invoice.paid', handlePaymentSuccess);

      // 在元件卸載時清理事件監聽器至關重要
      // 或在 subscription 物件變更時，以防止記憶體洩漏。
      return () => {
        subscription.off('invoice.paid', handlePaymentSuccess);
      };
    }
    // 如果 subscription 物件本身發生變化，此 effect 應該重新執行。
  }, [subscription, invoiceId]);

  return (
    <div>
      <h2>發票狀態</h2>
      <p>ID：{invoiceId}</p>
      <p>狀態：<strong>{status.toUpperCase()}</strong></p>
      {status === 'pending' && <p>等待付款確認...</p>}
      {status === 'paid' && <p>付款已確認！您的發票已結清。</p>}
    </div>
  );
}

export default InvoiceStatusTracker;
```