use-x-chat
Build professional AI chat interfaces using the useXChat Hook.
Install
mkdir -p .claude/skills/use-x-chat && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/12541" && unzip -o skill.zip -d .claude/skills/use-x-chat && rm skill.zipInstalls to .claude/skills/use-x-chat
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
专注讲解如何使用 useXChat Hook,包括自定义 Provider 的集成、消息管理、错误处理、多会话管理等Key capabilities
- →Integrate custom Provider
- →Manage messages
- →Handle errors
- →Manage multiple sessions
- →Map `MessageInfo` to `Bubble.List` format
- →Render complex `ChatMessage` objects
How it works
The skill integrates a custom chat provider, manages messages, and handles errors using `useXChat` Hook. It maps `MessageInfo` to the `Bubble.List` format and renders complex `ChatMessage` objects.
Inputs & outputs
When to use use-x-chat
- →Implementing custom chat providers
- →Handling chat error states
- →Building multi-session chat interfaces
About this skill
🎯 技能定位
核心定位:使用
useXChatHook 构建专业级 AI 对话应用 前置要求:已具备自定义 Chat Provider(参考 x-chat-provider 技能)
目录导航
🚀 快速开始
1. 依赖管理
- @ant-design/x-sdk: 2.2.2+
- @ant-design/x: 最新版(UI 组件)
npm install @ant-design/x-sdk@latest @ant-design/x@latest
2. 三步集成
步骤1:准备 Provider
由 x-chat-provider 技能负责。注意 XRequest 必须传 manual: true:
import { MyChatProvider } from './MyChatProvider';
import { XRequest } from '@ant-design/x-sdk';
// ⚠️ manual: true 是必须的
const provider = new MyChatProvider({
request: XRequest('https://your-api.com/chat', { manual: true }),
});
步骤2:基础使用
import { useXChat } from '@ant-design/x-sdk';
const ChatComponent = () => {
const { messages, onRequest, isRequesting } = useXChat({
provider,
requestPlaceholder: (_, { messages }) => ({
content: '正在思考中...',
role: 'assistant',
}),
requestFallback: (_, { error, messageInfo }) => {
if (error.name === 'AbortError') {
return { content: messageInfo?.message?.content || '已取消回复', role: 'assistant' };
}
return { content: '网络异常,请稍后重试', role: 'assistant' };
},
});
return (
<div>
{messages.map((msg) => (
<div key={msg.id}>
{msg.message.role}: {msg.message.content}
</div>
))}
<button onClick={() => onRequest({ query: '你好' })}>发送</button>
</div>
);
};
步骤3:UI 集成
⚠️
messages是MessageInfo<ChatMessage>[],不能直接传给Bubble.List。需要映射为{ key, role, content, loading }格式。Bubble.List使用role属性(不是roles)配置角色样式。
import { Bubble, Sender } from '@ant-design/x';
const ChatUI = () => {
const { messages, onRequest, isRequesting, abort } = useXChat({ provider });
return (
<div style={{ height: 600 }}>
<Bubble.List
// ✅ 正确:使用 role(不是 roles)
role={{
user: { placement: 'end' },
assistant: { placement: 'start' },
}}
items={messages.map(({ id, message, status }) => ({
key: id,
role: message.role, // 用于匹配 role 配置
content: message.content, // 消息内容
loading: status === 'loading', // 加载动画
}))}
/>
<Sender
loading={isRequesting}
onSubmit={(content) => onRequest({ query: content })}
onCancel={abort}
/>
</div>
);
};
当 ChatMessage 是对象类型时(非字符串)
当 ChatMessage 是复杂对象(如有 content、attachments 等字段),需用 contentRender 渲染:
<Bubble.List
role={{
assistant: {
placement: 'start',
// contentRender 接收 content 参数,就是 message 字段本身
contentRender(content: MyMessage) {
return (
<div>
<div>{content.content}</div>
{content.attachments?.map((a) => (
<FileCard key={a.url} name={a.name} />
))}
</div>
);
},
},
user: {
placement: 'end',
contentRender(content: MyMessage) {
return content.content;
},
},
}}
items={messages.map(({ id, message, status }) => ({
key: id,
role: message.role,
content: message, // ⚠️ 传整个 message 对象,contentRender 会处理渲染
loading: status === 'loading',
}))}
/>
🧩 核心概念
数据模型
⚠️ 重要:
messages类型是MessageInfo<ChatMessage>[],消息内容在msg.message中
interface MessageInfo<ChatMessage> {
id: number | string; // 消息唯一标识
message: ChatMessage; // 实际消息内容(你的 ChatMessage 类型)
status: MessageStatus; // 消息状态
extraInfo?: AnyObject; // 扩展信息(注意:是 extraInfo,不是 extra)
}
type MessageStatus = 'local' | 'loading' | 'updating' | 'success' | 'error' | 'abort';
// local: 用户发送的本地消息
// loading: AI 回复占位中(requestPlaceholder 对应此状态)
// updating: AI 正在流式输出
// success: AI 回复完成
// error: 请求失败
// abort: 用户主动取消
useXChat 配置项
| 配置项 | 类型 | 说明 |
|---|---|---|
provider | AbstractChatProvider<ChatMessage, Input, Output> | 必填,Provider 实例 |
conversationKey | string | 会话唯一标识,多会话必填 |
defaultMessages | DefaultMessageInfo[] | () => ... | async () => ... | 默认展示消息,支持异步加载 |
requestPlaceholder | ChatMessage | (requestParams, { messages }) => ChatMessage | 请求中的占位消息 |
requestFallback | ChatMessage | (requestParams, { error, errorInfo, messages, messageInfo }) => ChatMessage | Promise<ChatMessage> | 请求失败/中止时的兜底消息 |
parser | (message: ChatMessage) => BubbleMessage | BubbleMessage[] | 将 ChatMessage 转为组件消费格式,支持一转多 |
requestFallback中messageInfo类型为MessageInfo<ChatMessage>,是请求失败时正在更新的那条消息。requestFallback同时处理网络错误(error)和主动取消(error.name === 'AbortError')。
useXChat 返回值
| 返回值 | 类型 | 说明 |
|---|---|---|
messages | MessageInfo<ChatMessage>[] | 消息列表,需映射后传给 Bubble.List |
parsedMessages | MessageInfo<ParsedMessage>[] | 经过 parser 转译后的消息列表(有 parser 时用这个) |
onRequest | (params: Partial<Input>, opts?: { extraInfo: AnyObject }) => void | 添加消息并触发请求 |
isRequesting | boolean | 是否正在请求 |
abort | () => void | 中止当前请求 |
setMessages | (messages: Partial<MessageInfo<ChatMessage>>[]) => void | 直接修改消息列表,不触发请求 |
setMessage | (id: string | number, info: Partial<MessageInfo<ChatMessage>>) => void | 修改单条消息,不触发请求 |
removeMessage | (id: string | number) => boolean | 删除某条消息,返回是否删除成功 |
onReload | (id: string | number, params: Partial<Input>, opts?: { extraInfo: AnyObject }) => void | 重新生成某条 AI 回复 |
queueRequest | (conversationKey: string | symbol, params: Partial<Input>, opts?: { extraInfo: AnyObject }) => void | 队列化请求,等待会话初始化后发送 |
isDefaultMessagesRequesting | boolean | 默认消息是否在异步加载中 |
🔧 核心功能详解
核心功能参考 CORE.md
🗂️ 多会话管理
useXConversations Hook
useXConversations 是 @ant-design/x-sdk 提供的会话列表管理 Hook,与 useXChat 配合实现多会话:
import { useXConversations } from '@ant-design/x-sdk';
import type { ConversationData } from '@ant-design/x-sdk';
const {
conversations, // ConversationData[]:会话列表
activeConversationKey, // string:当前激活会话的 key
setActiveConversationKey, // (key: string) => void:切换会话
addConversation, // ( ConversationData, placement?) => boolean
removeConversation, // (key: string) => boolean
setConversation, // (key: string, data: ConversationData) => boolean
getConversation, // (key: string) => ConversationData | undefined
setConversations, // (list: ConversationData[]) => void
getMessages, // (key: string) => MessageInfo[] | undefined(跨组件读取消息)
} = useXConversations({
defaultConversations: [
{ key: 'conv-1', label: '会话 1' },
{ key: 'conv-2', label: '会话 2' },
],
defaultActiveConversationKey: 'conv-1',
});
多会话完整模式
import { useXChat, useXConversations } from '@ant-design/x-sdk';
import { OpenAIChatProvider, XRequest } from '@ant-design/x-sdk';
import { Bubble, Conversations, Sender } from '@ant-design/x';
import React, { useEffect, useRef } from 'react';
// ⚠️ 每个会话必须有独立的 Provider 实例,否则状态会混用
const providerCache = new Map<string, OpenAIChatProvider>();
function getProvider(key: string): OpenAIChatProvider {
if (!providerCache.has(key)) {
providerCache.set(
key,
new OpenAIChatProvider({
request: XRequest(BASE_URL, { manual: true, params: { model: 'gpt-4o', stream: true } }),
}),
);
}
return providerCache.get(key)!;
}
const App = () => {
const senderRef = useRef<any>(null);
const { conversations, activeConversationKey, setActiveConversationKey, addConversation } =
useXConversations({
defaultConversations: [{ key: 'conv-1', label: '新对话' }],
defaultActiveConversationKey: 'conv-1',
});
const { messages, onRequest, isRequesting, abort, queueRequest } = useXChat({
provider: getProvider(activeConversationKey),
conversationKey: activeConversationKey,
// 异步加载默认消息
defaultMessages: async ({ conversationKey }) => {
// 根据 conversationKey 从服务器加载历史消息
return [];
},
requestFallback: (_, { error, messageInfo }) => {
if (error.name === 'AbortError') {
return { content: messageInfo?.message?.content || '已取消', role: 'assistant' };
}
return { content: '请求失败', role: 'assistant' };
},
});
// 切换会话时清空输入框
useEffect(() => {
senderRef.current?.clear?.();
}, [activeConversationKey]);
const handleNewConversation = () => {
const newKey = `conv-${Date.now()}`;
addConversation({ key: newKey, label: `新对话 ${conversations.length + 1}` });
setActiveConversationKey(newKey);
};
return (
<div style={{ display: 'flex', height: '100vh' }}>
<Conversations
items={conversations}
activeKey={activeConversationKey}
onActiveChange={setActiveConversationKey}
creation={{ onClick: handleNewConversation }}
/>
<div style={{ flex: 1, display: 'flex', flexDirection: 'column' }}>
<Bubble.List
role={{ assistant: { placement: 'start' }, user: { placement: 'end' } }}
items={messages.map(({ id, message, status }) => ({
key: id,
role: message.role,
content: message.content,
loading: status === 'loading',
}))}
/>
<Sender
ref={senderRef}
loading={isRequesting}
onCancel={abort}
onSubmit={(val) => {
onRequest({ messages: [{ role: 'user', content: val }] });
}}
/>
</div>
</div>
);
};
queueRequest:会话切换后延迟发送
// 场景:用户切换到新会话,同时触发一条初始消息
// queueRequest 会等 defaultMessages 异步加载完成后,再发送请求
const handleNewConversationWithFirstMessage = () => {
const newKey = `conv-${Date.now()}`;
addConversation({ key: newKey, label: '新对话' });
setActiveConversationKey(newKey);
// 把消息加入队列,等 newKey 会话的 defaultMessages 加载完后自动发送
queueRequest(newKey, {
messages: [{ role: 'user
---
*Content truncated.*
When not to use it
- →When not building professional AI dialogue applications
- →When not using `useXChat` Hook
- →When a custom Chat Provider is not already available
Prerequisites
Limitations
- →Requires a custom Chat Provider to be already available
- →Requires `XRequest` in the Provider to be configured with `manual: true`
- →Requires `Bubble.List` to use the `role` property for styling
How it compares
This workflow provides specific guidance on integrating `useXChat` with custom providers and UI components, including handling complex message types and multi-session management, which is more detailed than a basic chat implementation.
Compared to similar skills
use-x-chat side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| use-x-chat (this skill) | 0 | 3mo | Review | Advanced |
| convex-realtime | 1 | 6mo | No flags | Intermediate |
| wagmi-development | 1 | 6mo | Review | Advanced |
| query-layer | 1 | 2mo | No flags | Advanced |
Try saying
Example prompts that trigger this skill in your AI assistant.
You might also like
convex-realtime
waynesutton
Patterns for building reactive apps including subscription management, optimistic updates, cache behavior, and paginated queries with cursor-based loading
wagmi-development
wevm
Creates Wagmi features across all layers - core actions, query options, framework bindings. Use when adding new actions, hooks, or working across packages/core, packages/react, packages/vue.
query-layer
EpicenterHQ
Query layer patterns for consuming services with TanStack Query, error transformation, and runtime dependency injection. Use when implementing queries/mutations, transforming service errors for UI, or adding reactive data management.
lifi-dev
mashharuki
>
create-react-component
OpenCTI-Platform
Use when: creating a new Relay-connected React component, defining a GraphQL fragment, or wiring a component to a query
frontend-api-integration-patterns
TJSNDHU
Production-ready patterns for integrating frontend applications with backend APIs, including race condition handling, request cancellation, retry strategies, error normalization, and UI state management.