跳至主要內容
入門

NIP-25 反應

深入了解 Nostr 的反應系統,按讚、表情符號反應和反應統計。

8 分鐘

什麼是 NIP-25?

NIP-25 定義了 Nostr 中的反應(Reactions)機制,讓用戶可以對事件表達 喜歡、不喜歡或使用表情符號反應。反應是 kind 7 事件,透過標籤引用目標事件。

核心概念: 反應使用 content 欄位表達反應類型:"+" 表示喜歡,"-" 表示不喜歡, 或任何表情符號如 "👍"、"❤️"、"🔥"。

事件結構

{
  "kind": 7,
  "content": "+",                    // 或 "-" 或表情符號
  "tags": [
    ["e", "<event-id>", "<relay>"],  // 被反應的事件
    ["p", "<event-author-pubkey>"]   // 事件作者
  ],
  "created_at": 1234567890,
  "pubkey": "<reactor-pubkey>",
  "id": "...",
  "sig": "..."
}

反應類型

Content 含義 說明
+ 喜歡 / 按讚 正面反應,通常顯示為愛心或讚
- 不喜歡 負面反應,部分客戶端可能不顯示
👍 ❤️ 🔥 😂 😢 表情反應 任何 Unicode 表情符號
:custom: 自訂表情 需配合 emoji 標籤使用

範例

按讚

{
  "kind": 7,
  "content": "+",
  "tags": [
    ["e", "abc123...", "wss://relay.damus.io"],
    ["p", "def456..."]
  ]
}

表情反應

{
  "kind": 7,
  "content": "🔥",
  "tags": [
    ["e", "abc123...", "wss://relay.damus.io"],
    ["p", "def456..."]
  ]
}

自訂表情

{
  "kind": 7,
  "content": ":sats:",
  "tags": [
    ["e", "abc123..."],
    ["p", "def456..."],
    ["emoji", "sats", "https://example.com/sats.png"]
  ]
}

// emoji 標籤格式:["emoji", "shortcode", "image-url"]

程式碼範例

發送反應

async function sendReaction(targetEvent, reaction = '+') {
  const event = {
    kind: 7,
    created_at: Math.floor(Date.now() / 1000),
    content: reaction,
    tags: [
      ['e', targetEvent.id, 'wss://relay.damus.io'],
      ['p', targetEvent.pubkey]
    ]
  }

  // 簽名並發送
  const signedEvent = await window.nostr.signEvent(event)
  relay.send(JSON.stringify(['EVENT', signedEvent]))

  return signedEvent
}

// 使用
await sendReaction(somePost, '❤️')  // 愛心反應
await sendReaction(somePost, '+')   // 按讚
await sendReaction(somePost, '🚀')  // 火箭反應

查詢反應

// 查詢特定事件的所有反應
["REQ", "reactions", {
  "kinds": [7],
  "#e": ["<event-id>"]
}]

// 查詢我收到的所有反應
["REQ", "my-reactions", {
  "kinds": [7],
  "#p": ["<my-pubkey>"]
}]

// 查詢特定用戶發出的反應
["REQ", "user-reactions", {
  "kinds": [7],
  "authors": ["<user-pubkey>"]
}]

統計反應

function countReactions(reactions) {
  const counts = {
    likes: 0,      // + 反應
    dislikes: 0,   // - 反應
    emojis: {}     // 其他表情
  }

  for (const r of reactions) {
    if (r.content === '+') {
      counts.likes++
    } else if (r.content === '-') {
      counts.dislikes++
    } else {
      counts.emojis[r.content] = (counts.emojis[r.content] || 0) + 1
    }
  }

  return counts
}

// 結果範例
// {
//   likes: 42,
//   dislikes: 2,
//   emojis: { '🔥': 10, '❤️': 8, '😂': 5 }
// }

反應到其他事件類型

NIP-25 可以對任何事件類型反應,不只是貼文:

// 反應到長文 (kind 30023)
{
  "kind": 7,
  "content": "👏",
  "tags": [
    ["e", "<article-event-id>"],
    ["p", "<author-pubkey>"],
    ["a", "30023:<author>:<d-tag>", "wss://relay.com"]
  ]
}

// "a" 標籤用於可替換事件,確保反應指向正確的內容

UI 設計考量

反應選擇器

提供快速按讚按鈕和表情選擇器

👍 ❤️ 😂 😢 😡 🔥

反應計數

顯示每種反應的數量

❤️ 42 🔥 15 😂 8

反應列表

點擊可查看誰給了反應

Alice, Bob 和其他 40 人

我的反應

高亮顯示用戶自己的反應

已按讚(點擊取消)

刪除反應

使用 kind 5(刪除事件)來撤回反應:

{
  "kind": 5,
  "content": "取消反應",
  "tags": [
    ["e", "<reaction-event-id>"]  // 要刪除的反應事件
  ]
}

// 注意:中繼器可能不會立即刪除
// 客戶端應該檢查 kind 5 事件來過濾已刪除的反應

與 Zaps 的關係

特性 NIP-25 反應 NIP-57 Zaps
類型 社交互動 金錢打賞
成本 免費 比特幣(聰)
Kind 7 9735
用途 表達情感 經濟支持

提示: 許多客戶端將 "+" 反應顯示為愛心圖示。如果你想支持更多表情反應, 確保你的 UI 可以正確渲染各種 Unicode 表情符號。

已複製連結
已複製到剪貼簿