diff --git a/frontend/components/layout/AppLayout.tsx b/frontend/components/layout/AppLayout.tsx index 1d16e5b4..a32332b2 100644 --- a/frontend/components/layout/AppLayout.tsx +++ b/frontend/components/layout/AppLayout.tsx @@ -685,7 +685,7 @@ function AppLayoutInner({ children }: AppLayoutProps) { const uiMenus = user ? convertMenuToUI(currentMenus, user as ExtendedUserInfo) : []; - // 활성 탭에 해당하는 메뉴가 속한 부모 메뉴 자동 확장 + // 활성 탭이 바뀔 때만 해당 부모 메뉴 자동 확장 (collapse 후 즉시 재펼침 방지) useEffect(() => { if (!activeTab || uiMenus.length === 0) return; @@ -693,19 +693,25 @@ function AppLayoutInner({ children }: AppLayoutProps) { for (const menu of uiMenus) { if (menu.hasChildren && menu.children) { const hasActiveChild = menu.children.some((child: any) => isMenuActive(child)); - if (hasActiveChild && !expandedMenus.has(menu.id)) { - toExpand.push(menu.id); - } + if (hasActiveChild) toExpand.push(menu.id); } } if (toExpand.length > 0) { setExpandedMenus((prev) => { + let changed = false; const next = new Set(prev); - toExpand.forEach((id) => next.add(id)); - return next; + toExpand.forEach((id) => { + if (!next.has(id)) { + next.add(id); + changed = true; + } + }); + return changed ? next : prev; }); } - }, [activeTab, uiMenus, isMenuActive, expandedMenus]); + // expandedMenus / uiMenus / isMenuActive 는 의존성에서 제외 — 활성 탭 변경 시에만 재평가 + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [activeTab?.id]); if (!user) { return (