跳至主要内容

自訂 Footer

renderFooter 完全取代預設 footer。當你需要客製整個輸入區(例如改成 單行 input、加上自製語音按鈕、改變排版邏輯)時用它;只是想在送出按鈕 後面加額外按鈕,請改用 footerEndActions

完全取代 Footer

用 renderFooter 直接接管 footer 區域:內建 textarea、送出按鈕、圖片 / 文件上傳、export、麥克風、drag-drop、IME 保護、footerEndActions 都不再渲染,整塊由 renderer 自己負責。

  • 用 useAsgardContext() 取得 sendMessage / isConnecting / inputPlaceholder
  • 用 pendingInputValue + setPendingInputValue 接收外部塞入的文字(例如 quick prompt)
  • isConnecting 時禁用送出,避免重複送訊息
  • IME 組字保護:Enter 在 isComposing 時不送出
聊天機器人載入中…

取代的內建功能

renderFooter完全取代而不是疊加:

  • 內建 textarea 與自動高度
  • 送出按鈕、麥克風按鈕
  • 圖片上傳、文件上傳、export 對話紀錄
  • Drag-and-drop 上傳整合
  • IME 組字保護(避免中文打字途中按 Enter 直接送出)
  • footerEndActions 槽位

以上元件全部不再渲染,由 renderer 自己負責。

程式範例

import {
Chatbot,
useAsgardContext,
type ChatbotRef,
} from "@asgard-js/react";
import { useEffect, useRef, useState } from "react";

function MyFooter() {
const {
sendMessage,
isConnecting,
pendingInputValue,
setPendingInputValue,
inputPlaceholder,
} = useAsgardContext();

const [value, setValue] = useState("");
const textareaRef = useRef<HTMLTextAreaElement>(null);

// 接收外部透過 ChatbotRef.setInputValue 塞進來的文字
useEffect(() => {
if (pendingInputValue == null) return;
setValue(pendingInputValue);
setPendingInputValue(null);
textareaRef.current?.focus();
}, [pendingInputValue, setPendingInputValue]);

const submit = () => {
const text = value.trim();
if (!text || isConnecting) return;
sendMessage?.({ text });
setValue("");
};

return (
<div className="footer">
<textarea
ref={textareaRef}
placeholder={inputPlaceholder}
value={value}
onChange={(e) => setValue(e.target.value)}
onKeyDown={(e) => {
// IME 組字途中不送出
if (
e.key === "Enter" &&
!e.shiftKey &&
!e.nativeEvent.isComposing
) {
e.preventDefault();
submit();
}
}}
rows={1}
/>
<button
onClick={submit}
disabled={!value.trim() || isConnecting}
>
送出
</button>
</div>
);
}

function Demo() {
const chatbotRef = useRef<ChatbotRef>(null);
return (
<Chatbot
ref={chatbotRef}
renderFooter={() => <MyFooter />}
{...rest}
/>
);
}

useAsgardContext 常用欄位

欄位型別說明
sendMessage(params) => void送出訊息;undefined 代表 preview / 未連線
isConnectingboolean是否正在等待回覆,建議用它禁用送出按鈕
pendingInputValuestring | null外部透過 ChatbotRef.setInputValue 推進來的文字
setPendingInputValue(v: string | null) => void消化掉 pending 值後請把它清成 null
inputPlaceholderstringChatbot props 傳入的 placeholder
messagesMap<string, ConversationMessage>所有訊息(如果你要做 token 計數等用途)

renderMenu / ChatbotRef.setInputValue 串接

這個 demo 同時用了 renderMenu 列出快速提問。按鈕透過 chatbotRef.current?.setInputValue(prompt) 把文字塞進 SDK 內部的 pendingInputValue,再由你的自訂 footer 消化掉,做到「點選 → 文字填入 輸入框 → 使用者再決定要不要送」的流程。

什麼時候不要用 renderFooter

  • 只想在送出鈕旁加按鈕:用 footerEndActions, 內建邏輯完全保留。
  • 完全跳過 Chatbot UI:用 Headless 模式,自己組裝整個畫面。