mirror of
https://gitee.com/wanwujie/deer-flow
synced 2026-04-27 15:54:48 +08:00
fix(chat): update navigation method to prevent state loss during thread remount (#1107)
This commit is contained in:
@@ -43,6 +43,7 @@ export default function AgentChatPage() {
|
|||||||
context: { ...settings.context, agent_name: agent_name },
|
context: { ...settings.context, agent_name: agent_name },
|
||||||
onStart: () => {
|
onStart: () => {
|
||||||
setIsNewThread(false);
|
setIsNewThread(false);
|
||||||
|
// ! Important: Never use next.js router for navigation in this case, otherwise it will cause the thread to re-mount and lose all states. Use native history API instead.
|
||||||
history.replaceState(
|
history.replaceState(
|
||||||
null,
|
null,
|
||||||
"",
|
"",
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useParams } from "next/navigation";
|
|
||||||
import { useEffect, useRef, useState } from "react";
|
|
||||||
|
|
||||||
import { PromptInputProvider } from "@/components/ai-elements/prompt-input";
|
import { PromptInputProvider } from "@/components/ai-elements/prompt-input";
|
||||||
import { ArtifactsProvider } from "@/components/workspace/artifacts";
|
import { ArtifactsProvider } from "@/components/workspace/artifacts";
|
||||||
import { SubtasksProvider } from "@/core/tasks/context";
|
import { SubtasksProvider } from "@/core/tasks/context";
|
||||||
@@ -12,24 +9,8 @@ export default function ChatLayout({
|
|||||||
}: {
|
}: {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
const { thread_id } = useParams<{ thread_id: string }>();
|
|
||||||
const prevThreadId = useRef(thread_id);
|
|
||||||
|
|
||||||
// Increment only when navigating TO "new" from a non-"new" route.
|
|
||||||
// This forces a full remount of the subtree for a fresh new-chat state,
|
|
||||||
// without remounting when the URL transitions from "new" → actual-id
|
|
||||||
// (which would interrupt streaming).
|
|
||||||
const [generation, setGeneration] = useState(0);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (thread_id === "new" && prevThreadId.current !== "new") {
|
|
||||||
setGeneration((g) => g + 1);
|
|
||||||
}
|
|
||||||
prevThreadId.current = thread_id;
|
|
||||||
}, [thread_id]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SubtasksProvider key={generation}>
|
<SubtasksProvider>
|
||||||
<ArtifactsProvider>
|
<ArtifactsProvider>
|
||||||
<PromptInputProvider>{children}</PromptInputProvider>
|
<PromptInputProvider>{children}</PromptInputProvider>
|
||||||
</ArtifactsProvider>
|
</ArtifactsProvider>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useRouter } from "next/navigation";
|
|
||||||
import { useCallback } from "react";
|
import { useCallback } from "react";
|
||||||
|
|
||||||
import { type PromptInputMessage } from "@/components/ai-elements/prompt-input";
|
import { type PromptInputMessage } from "@/components/ai-elements/prompt-input";
|
||||||
@@ -26,7 +25,6 @@ import { cn } from "@/lib/utils";
|
|||||||
|
|
||||||
export default function ChatPage() {
|
export default function ChatPage() {
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const router = useRouter();
|
|
||||||
const [settings, setSettings] = useLocalSettings();
|
const [settings, setSettings] = useLocalSettings();
|
||||||
|
|
||||||
const { threadId, isNewThread, setIsNewThread, isMock } = useThreadChat();
|
const { threadId, isNewThread, setIsNewThread, isMock } = useThreadChat();
|
||||||
@@ -40,11 +38,8 @@ export default function ChatPage() {
|
|||||||
isMock,
|
isMock,
|
||||||
onStart: () => {
|
onStart: () => {
|
||||||
setIsNewThread(false);
|
setIsNewThread(false);
|
||||||
// Use router.replace so Next.js Router's internal state is updated.
|
// ! Important: Never use next.js router for navigation in this case, otherwise it will cause the thread to re-mount and lose all states. Use native history API instead.
|
||||||
// This ensures subsequent "New Chat" clicks are treated as a real
|
history.replaceState(null, "", `/workspace/chats/${threadId}`);
|
||||||
// cross-route navigation (actual-id → "new") rather than a no-op
|
|
||||||
// same-path navigation, which was causing stale content to persist.
|
|
||||||
router.replace(`/workspace/chats/${threadId}`);
|
|
||||||
},
|
},
|
||||||
onFinish: (state) => {
|
onFinish: (state) => {
|
||||||
if (document.hidden || !document.hasFocus()) {
|
if (document.hidden || !document.hasFocus()) {
|
||||||
|
|||||||
Reference in New Issue
Block a user