From e66d4aa18d5e4485876524dadb5d4c5640a8442e Mon Sep 17 00:00:00 2001 From: tyanxie <494966054@qq.com> Date: Sat, 27 Jun 2026 11:07:16 +0800 Subject: [PATCH] =?UTF-8?q?fix(web):=20=E4=BF=AE=E5=A4=8D=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=E5=8D=A1=E7=89=87=E5=BC=B9=E7=AA=97=E5=9C=A8=E6=89=A7?= =?UTF-8?q?=E8=A1=8C=E5=AE=8C=E6=88=90=E6=97=B6=E8=A2=AB=E6=84=8F=E5=A4=96?= =?UTF-8?q?=E5=85=B3=E9=97=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit message_end 时复用 streamingEntry 的 render key,避免 React 因 key 变化重建组件导致 Modal 内部状态丢失。 --- .../InstanceView/useConversation.ts | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/web/src/components/InstanceView/useConversation.ts b/src/web/src/components/InstanceView/useConversation.ts index 2c32ca2..9b292e0 100644 --- a/src/web/src/components/InstanceView/useConversation.ts +++ b/src/web/src/components/InstanceView/useConversation.ts @@ -65,6 +65,8 @@ export function useConversation( const [streamingEntry, setStreamingEntry] = useState( null, ); + // 追踪当前 streamingEntry 的 renderKey,避免闭包读取 state 过时 + const streamingKeyRef = useRef(null); const [loadState, setLoadState] = useState("idle"); const [errorMessage, setErrorMessage] = useState(null); const [hasMore, setHasMore] = useState(false); @@ -187,13 +189,13 @@ export function useConversation( case "message_start": { const message = d.message as SessionEntry["message"]; if (!message || message.role !== "assistant") break; - setStreamingEntry( - ensureRenderKey( - id, - { type: "message", timestamp: new Date().toISOString(), message }, - "streaming", - ), + const entry = ensureRenderKey( + id, + { type: "message", timestamp: new Date().toISOString(), message }, + "streaming", ); + streamingKeyRef.current = entry.__renderKey ?? entry.id ?? null; + setStreamingEntry(entry); break; } case "message_update": { @@ -215,13 +217,18 @@ export function useConversation( case "message_end": { const message = d.message as SessionEntry["message"]; if (message) { - const entry = ensureRenderKey( - id, - { type: "message", timestamp: new Date().toISOString(), message }, - "live", - ); + // 复用 streamingEntry 的 key,避免 React 重建组件导致弹窗状态丢失 + const stableKey = + streamingKeyRef.current ?? nextRenderKey(id, "live"); + const entry: SessionEntry = { + type: "message", + timestamp: new Date().toISOString(), + message, + __renderKey: stableKey, + }; setEntries((prev) => [...prev, entry]); } + streamingKeyRef.current = null; setStreamingEntry(null); break; }