React SDK (@asgard-js/react)
@asgard-js/react 提供 React Hook 與現成的聊天室 UI 元件,讓 React 應用程式能快速整合 Asgard 聊天功能。
安裝
@asgard-js/react 以 @asgard-js/core 為 peer dependency,請同時安裝:
npm install @asgard-js/react @asgard-js/core
AsgardProvider 設定
在應用程式根層級(或需要聊天功能的元件樹根部)加入 AsgardProvider:
import { AsgardProvider } from '@asgard-js/react';
function App() {
return (
<AsgardProvider
baseUrl="https://api.asgard.example.com"
namespace="my-namespace"
botProviderName="my-bot"
apiKey="your-api-key"
>
<YourApp />
</AsgardProvider>
);
}
AsgardProvider Props
| Prop | 型別 | 必填 | 說明 |
|---|---|---|---|
baseUrl | string | 是 | API 伺服器基礎 URL |
namespace | string | 是 | 命名空間識別碼 |
botProviderName | string | 是 | Bot Provider 名稱 |
apiKey | string | 是 | API 金鑰 |
initialChannelId | string | 否 | 預設 channel ID,用於持續對話 |
useAsgard Hook
在 AsgardProvider 內的任何元件都可使用 useAsgard Hook 存取聊天狀態與操作:
import { useAsgard } from '@asgard-js/react';
function ChatWidget() {
const { sendMessage, messages, isLoading, error } = useAsgard();
const handleSend = async () => {
await sendMessage('請介紹一下你的功能');
};
return (
<div>
{messages.map((msg, index) => (
<div key={index} className={`message ${msg.role}`}>
{msg.content}
</div>
))}
{isLoading && <div className="loading">機器人正在回應中...</div>}
{error && <div className="error">錯誤:{error.message}</div>}
<button onClick={handleSend} disabled={isLoading}>
發送
</button>
</div>
);
}
useAsgard 回傳值
| 屬性 | 型別 | 說明 |
|---|---|---|
sendMessage | (message: string, options?: SendOptions) => Promise<void> | 發送訊息 |
messages | Message[] | 對話紀錄陣列 |
isLoading | boolean | 是否正在等待或接收回應 |
error | Error | null | 最近一次錯誤,無錯誤時為 null |
resetChannel | () => void | 重置對話 channel |
channelId | string | 目前的 channel ID |
Message 型別
interface Message {
role: 'user' | 'assistant';
content: string;
timestamp: Date;
}
AsgardChat 元件
AsgardChat 是一個現成的完整聊天室 UI 元件,包含訊息列表、輸入框與發送按鈕:
import { AsgardProvider, AsgardChat } from '@asgard-js/react';
function App() {
return (
<AsgardProvider
baseUrl="https://api.asgard.example.com"
namespace="my-namespace"
botProviderName="my-bot"
apiKey="your-api-key"
>
<AsgardChat
placeholder="輸入訊息..."
welcomeMessage="您好!有什麼我可以幫您的嗎?"
height="600px"
/>
</AsgardProvider>
);
}
AsgardChat Props
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
placeholder | string | '輸入訊息...' | 輸入框 placeholder 文字 |
welcomeMessage | string | — | 初始歡迎訊息 |
height | string | '500px' | 聊天室高度 |
className | string | — | 自訂 CSS class |
style | CSSProperties | — | 自訂行內樣式 |
使用 Hook 自訂 UI
如果 AsgardChat 的樣式不符需求,可以直接使用 useAsgard Hook 搭配自訂 UI:
import { useState } from 'react';
import { useAsgard } from '@asgard-js/react';
function CustomChat() {
const [input, setInput] = useState('');
const { sendMessage, messages, isLoading, error, resetChannel } = useAsgard();
const handleSubmit = async (e) => {
e.preventDefault();
if (!input.trim() || isLoading) return;
const text = input;
setInput('');
await sendMessage(text);
};
return (
<div className="custom-chat">
<div className="chat-header">
<h3>客服助理</h3>
<button onClick={resetChannel}>新對話</button>
</div>
<div className="message-list">
{messages.map((msg, i) => (
<div key={i} className={`bubble ${msg.role}`}>
<span>{msg.content}</span>
<time>{msg.timestamp.toLocaleTimeString()}</time>
</div>
))}
{isLoading && <div className="bubble assistant typing">...</div>}
</div>
{error && (
<div className="error-banner">
{error.message}
</div>
)}
<form onSubmit={handleSubmit} className="input-area">
<input
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="輸入訊息..."
disabled={isLoading}
/>
<button type="submit" disabled={isLoading || !input.trim()}>
發送
</button>
</form>
</div>
);
}
SSR 注意事項
@asgard-js/react 在瀏覽器端運作,使用 SSE 等瀏覽器 API。在 SSR 環境(如 Docusaurus 或 Next.js)中,需要避免在伺服器端渲染聊天元件。
Docusaurus
使用 BrowserOnly 元件包裹:
import BrowserOnly from '@docusaurus/BrowserOnly';
function ChatPage() {
return (
<BrowserOnly fallback={<div>載入中...</div>}>
{() => {
const { AsgardProvider, AsgardChat } = require('@asgard-js/react');
return (
<AsgardProvider
baseUrl="https://api.asgard.example.com"
namespace="my-namespace"
botProviderName="my-bot"
apiKey="your-api-key"
>
<AsgardChat />
</AsgardProvider>
);
}}
</BrowserOnly>
);
}
Next.js
使用 dynamic import 並設定 ssr: false:
import dynamic from 'next/dynamic';
const AsgardChatWidget = dynamic(
() => import('../components/AsgardChatWidget'),
{ ssr: false }
);
export default function Page() {
return (
<main>
<AsgardChatWidget />
</main>
);
}
樣式自訂
使用 CSS Variables
AsgardChat 支援透過 CSS variables 調整外觀:
.asgard-chat {
--asgard-primary-color: #4f46e5;
--asgard-background: #ffffff;
--asgard-message-user-bg: #4f46e5;
--asgard-message-user-color: #ffffff;
--asgard-message-bot-bg: #f3f4f6;
--asgard-message-bot-color: #111827;
--asgard-border-radius: 12px;
--asgard-font-size: 14px;
}
使用 className 覆寫樣式
<AsgardChat
className="my-chat-widget"
style={{ borderRadius: '16px', boxShadow: '0 4px 24px rgba(0,0,0,0.1)' }}
/>