# 事件訂閱

OCAP Client 提供一個功能強大、即時的事件訂閱系統，讓您的應用程式能夠即時監聽鏈上活動。此功能基於 WebSockets 建立，提供與區塊鏈節點的持久連線，無需透過持續輪詢來檢查更新。

透過訂閱特定的事件主題，您可以接收到各種鏈上事件的即時通知，例如新交易建立、資產轉移或代幣交換。這對於建構能即時回應區塊鏈狀態變化的互動式應用程式至關重要。若想深入了解觸發這些事件的原因，您可以參閱 [交易生命週期](./core-concepts-transaction-lifecycle.md)。


## 運作方式

在底層，當您首次訂閱事件時，OCAP Client 會自動與區塊鏈節點的指定端點建立 WebSocket 連線。此連線會保持活動狀態，讓節點能在事件發生時立即將事件資料推送至您的客戶端。

客戶端會為您管理 WebSocket 連線的生命週期。它會處理初始連線、發送心跳訊息以維持連線，並在連線中斷時嘗試重新連線。這確保了穩定可靠的事件流，而您只需進行最少的設定。


## 訂閱事件

若要開始監聽事件，請使用 `subscribe` 方法。您需要提供一個事件主題（用於識別事件的字串）和一個回呼函式，該函式將在每次收到事件時執行。

```javascript OCAP Client icon=logos:javascript
const client = new GraphQLClient('https://beta.abtnetwork.io/api/v2/gql');

const handleNewTransaction = (eventData) => {
  console.log('A new transaction was created on-chain:', eventData);
};

// 訂閱 'tx.create' 主題
client.subscribe('tx.create', handleNewTransaction);
```

### 方法簽章

**`subscribe(topic, callback)`**

<x-field-group>
  <x-field data-name="topic" data-type="string" data-required="true" data-desc="要訂閱的事件主題名稱。例如：'tx.create'。"></x-field>
  <x-field data-name="callback" data-type="Function" data-required="true" data-desc="接收到事件時要執行的函式。事件資料會作為第一個參數傳入。"></x-field>
</x-field-group>

### 常見事件主題

事件主題通常遵循 `tx.<transaction_type>` 的模式。以下是一些常見範例：

| Topic             | Description                  |
| ----------------- | ---------------------------- |
| `tx.create`       | 任何新交易成功處理並加入區塊時觸發。           |
| `tx.transfer_v2`  | 當 `transferV2` 交易發生時特別觸發。    |
| `tx.exchange_v2`  | 當 `exchangeV2`（原子交換）交易完成時觸發。 |
| `tx.create_asset` | 當新資產（NFT）被建立時觸發。             |


## 取消訂閱事件

當不再需要訂閱時，最好進行清理，特別是在元件會掛載和卸載的單頁應用程式中。這可以防止記憶體洩漏和不必要的處理。您可以使用 `unsubscribe` 方法來移除訂閱。

```javascript OCAP Client icon=logos:javascript
// 若要移除特定的監聽器，請傳入相同的回呼函式參考
client.unsubscribe('tx.create', handleNewTransaction);

// 若要移除特定主題的所有監聽器
client.unsubscribe('tx.create');
```

### 方法簽章

**`unsubscribe(topic, [callback])`**

<x-field-group>
  <x-field data-name="topic" data-type="string" data-required="true" data-desc="要取消訂閱的事件主題名稱。"></x-field>
  <x-field data-name="callback" data-type="Function" data-required="false" data-desc="選用。要移除的特定回呼函式。如果省略，將移除該主題的所有監聽器。"></x-field>
</x-field-group>


## 完整範例

以下是一個完整範例，示範了訂閱事件、觸發事件，然後取消訂閱的過程。

```javascript Event Subscription Lifecycle icon=logos:javascript
import GraphQLClient from '@ocap/client';
import { fromRandom } from '@ocap/wallet';

const main = async () => {
  const client = new GraphQLClient('https://beta.abtnetwork.io/api/v2/gql');
  const events = { txCreate: 0, txTransfer: 0 };

  // 1. 訂閱事件
  client.subscribe('tx.create', () => (events.txCreate += 1));
  client.subscribe('tx.transfer_v2', () => (events.txTransfer += 1));

  console.log('Subscribed to tx.create and tx.transfer_v2 events...');

  // 輔助函式，用於等待一小段時間
  const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
  await sleep(100); // 稍待片刻，以便訂閱註冊成功

  // 2. 執行一個會觸發事件的動作
  // 注意：這需要一個有資金的錢包。您可以從 https://faucet.abtnetwork.io/ 獲取測試代幣。
  const sender = fromRandom(); // 在實際應用中，請載入一個有資金的錢包
  // 在此範例中，我們假設該動作會成功。
  console.log('A transfer transaction would trigger the event handlers.');
  
  // 在實際情境中，成功轉帳後：
  // await client.transfer({ to: 'z1...', token: 1, wallet: sender });

  // 讓我們模擬在成功交易後事件計數器增加的情況
  events.txCreate = 1;
  events.txTransfer = 1;

  await sleep(100); // 等待事件處理完成

  // 3. 驗證事件處理函式是否被呼叫
  console.log(`tx.create was called ${events.txCreate} time(s).`);
  console.log(`tx.transfer_v2 was called ${events.txTransfer} time(s).`);

  // 4. 取消訂閱以進行清理
  client.unsubscribe('tx.create');
  client.unsubscribe('tx.transfer_v2');
  console.log('Unsubscribed from events.');
};

main().catch(console.error);
```


## 總結

事件訂閱是使用 OCAP Client 建構動態 dApp 的核心功能。它們提供了一個簡單而強大的 API，可透過可靠的 WebSocket 連線即時回應鏈上事件。透過使用 `subscribe` 和 `unsubscribe` 方法，您可以有效率地管理應用程式中的即時資料流。

有關如何建構和發送交易（進而產生這些事件）的更多詳細資訊，請參閱 [交易生命週期](./core-concepts-transaction-lifecycle.md) 文件。若要探索如何為您的使用者贊助交易費用（這在與事件監聽器結合使用時非常有用），請閱讀有關 [Gas 費用支付](./core-concepts-gas-payment.md) 的內容。
