/** * MessageItem — 单条消息路由组件 * * 根据消息 role 路由到对应的子组件渲染。 * * F1 性能优化: 使用 React.memo 包裹,避免流式 delta 触发历史消息重渲染。 * 浅比较策略:message 引用变化(store 仅替换最后一条)或 isStreaming 变化时才重渲染。 * 历史消息的 message 引用在 delta 流中保持不变,因此可跳过 re-render。 */ import { memo } from 'react'; import type { ChatMessage } from '@renderer/stores/agent-store'; import { UserMessage } from './UserMessage'; import { AssistantMessage } from './AssistantMessage'; import { SystemMessage } from './SystemMessage'; interface MessageItemProps { message: ChatMessage; isLast?: boolean; isStreaming?: boolean; } function MessageItemImpl({ message, isLast, isStreaming }: MessageItemProps): React.JSX.Element | null { switch (message.role) { case 'user': return ; case 'assistant': return ( ); case 'tool': // #38 修复: 与 AgentStore.setCurrentSession 的过滤逻辑保持一致, // 不在 UI 中渲染独立的 tool 消息卡片。 // tool 结果已包含在 assistant 消息的 toolCalls 中(见 AssistantMessage), // 独立的 tool 消息仅用于 LLM API 上下文,不需要在前端显示为独立卡片。 return null; case 'system': default: return ; } } /** * F1: memo 默认浅比较 props。 * - message 是对象引用,store 更新最后一条时只替换最后一条,历史消息引用不变 → 跳过 re-render * - isStreaming 是 boolean,流式过程中值不变(持续 true),流结束才变化一次 → 历史消息仅重渲染一次 * - isLast 是 boolean,仅在最后一条切换时变化 */ export const MessageItem = memo(MessageItemImpl);