From f7735e0b9cdb1b4d64f4416e1434015eb533c94b Mon Sep 17 00:00:00 2001 From: 7418 <7418@openclaw.ai> Date: Sat, 28 Feb 2026 13:30:20 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=85=B3=E9=97=AD?= =?UTF-8?q?=E6=9C=80=E5=90=8E=E4=B8=80=E4=B8=AA=E5=88=86=E5=B1=8F=E6=97=B6?= =?UTF-8?q?=20setState-during-render=20=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - removeFromSplit 中 setSplitSessions updater 内直接调用 router.replace 导致在渲染 AppShell 时触发 Router 组件状态更新 - 改为将导航目标存入 useRef,通过 useEffect 延迟执行 router.replace Co-Authored-By: Claude Opus 4.6 --- src/components/layout/AppShell.tsx | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/components/layout/AppShell.tsx b/src/components/layout/AppShell.tsx index 9f79fd1..58114b2 100644 --- a/src/components/layout/AppShell.tsx +++ b/src/components/layout/AppShell.tsx @@ -1,6 +1,6 @@ "use client"; -import { useState, useEffect, useCallback, useMemo } from "react"; +import { useState, useEffect, useCallback, useMemo, useRef } from "react"; import { usePathname, useRouter } from "next/navigation"; import { TooltipProvider } from "@/components/ui/tooltip"; import { NavRail } from "./NavRail"; @@ -208,14 +208,15 @@ export function AppShell({ children }: { children: React.ReactNode }) { }); }, [sessionId, sessionTitle, workingDirectory]); + const pendingNavigateRef = useRef(null); + const removeFromSplit = useCallback((removeId: string) => { setSplitSessions((prev) => { const next = prev.filter((s) => s.sessionId !== removeId); if (next.length <= 1) { - // Exit split mode + // Exit split mode — defer navigation to useEffect if (next.length === 1) { - // Navigate to the remaining session - router.replace(`/chat/${next[0].sessionId}`); + pendingNavigateRef.current = next[0].sessionId; } return []; } @@ -225,7 +226,16 @@ export function AppShell({ children }: { children: React.ReactNode }) { ); return next; }); - }, [router]); + }, []); + + // Deferred navigation after split exit (avoids setState-during-render) + useEffect(() => { + if (pendingNavigateRef.current) { + const target = pendingNavigateRef.current; + pendingNavigateRef.current = null; + router.replace(`/chat/${target}`); + } + }, [splitSessions, router]); const exitSplit = useCallback(() => { const firstSession = splitSessions[0];