Membangun Chat UI
Chat interface adalah pola UI paling umum untuk AI. Terlihat sederhana, tapi banyak detail UX yang perlu diperhatikan.
Komponen Utama
function ChatUI() {
const [messages, setMessages] = useState([]);
const [input, setInput] = useState("");
const [isLoading, setIsLoading] = useState(false);
const messagesEndRef = useRef(null);
// Auto-scroll ke bawah
useEffect(() => {
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
}, [messages]);
async function handleSubmit(e) {
e.preventDefault();
if (!input.trim() || isLoading) return;
const userMessage = { role: "user", content: input };
setMessages(prev => [...prev, userMessage]);
setInput("");
setIsLoading(true);
// Stream response
const assistantMessage = { role: "assistant", content: "" };
setMessages(prev => [...prev, assistantMessage]);
await streamChat([...messages, userMessage], (token) => {
setMessages(prev => {
const updated = [...prev];
updated[updated.length - 1].content += token;
return updated;
});
});
setIsLoading(false);
}
return (
<div className="flex flex-col h-screen">
<div className="flex-1 overflow-y-auto p-4">
{messages.map((m, i) => (
<MessageBubble key={i} message={m} />
))}
<div ref={messagesEndRef} />
</div>
<form onSubmit={handleSubmit} className="p-4 border-t">
<input value={input} onChange={e => setInput(e.target.value)} />
<button disabled={isLoading}>Kirim</button>
</form>
</div>
);
}
UX Details
- Typing indicator — Tunjukkan "AI sedang mengetik..." saat streaming
- Markdown rendering — AI sering output markdown (code blocks, lists, bold)
- Copy button — Untuk code blocks
- Regenerate — Tombol untuk minta ulang jawaban
- Stop generation — AbortController untuk cancel stream
- Error handling — "Gagal mengirim pesan. Coba lagi."
Stop Generation
const controller = new AbortController();
fetch("/api/chat", {
signal: controller.signal,
// ...
});
// User clicks "Stop"
controller.abort();