Skip to content

Managing Messages

useChat returns a setMessages function — the standard React state setter for the messages array. Use it for any programmatic manipulation beyond what the streaming lifecycle provides.

Reset the chat to an empty state:

const { messages, setMessages, sendMessage } = useChat({ api: "/chat" });
function handleNewChat() {
setMessages([]);
}
<button onClick={handleNewChat}>New Chat</button>

Remove a specific message by filtering it out:

function handleDelete(messageId: string) {
setMessages((prev) => prev.filter((msg) => msg.id !== messageId));
}
{messages.map((msg) => (
<div key={msg.id}>
{msg.parts.map((part, i) => {
switch (part.type) {
case "text":
return <span key={i}>{part.text}</span>;
default:
return null;
}
})}
<button onClick={() => handleDelete(msg.id)}>Delete</button>
</div>
))}

Update the parts of a specific message:

function handleEdit(messageId: string, newText: string) {
setMessages((prev) =>
prev.map((msg) =>
msg.id === messageId
? { ...msg, parts: [{ type: "text", text: newText }] }
: msg,
),
);
}

Insert a message at the beginning of the conversation:

function addWelcomeMessage() {
setMessages((prev) => [
{
id: "welcome",
role: "assistant",
parts: [{ type: "text", text: "Hello! How can I help you today?" }],
},
...prev,
]);
}

setMessages supports functional updates — the same pattern as React’s useState setter. Always use functional updates when the new state depends on the previous state:

// Good — uses previous state
setMessages((prev) => prev.filter((msg) => msg.role !== "assistant"));
// Bad — may use stale state
setMessages(messages.filter((msg) => msg.role !== "assistant"));
  • setMessages triggers a re-render with the new messages array
  • Changes made via setMessages are not sent to the backend — it only modifies local state
  • sendMessage is a no-op while a stream is in progress. If you need to clear messages and send a new one, call stop() first, then setMessages([]), then sendMessage(text) on the next render
  • The onMessage and onFinish callbacks are not triggered by setMessages — they only fire during the streaming lifecycle