fix(layout): use controlled sidebar openKeys to preserve manual expand/collapse across navigation

This commit is contained in:
2026-07-09 16:31:56 +08:00
parent d1d5b4681b
commit 5145c3e4b4

View File

@@ -1,4 +1,4 @@
import React, { useCallback, useMemo, useState } from 'react';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { Outlet, useNavigate, useLocation } from 'react-router-dom';
import { Layout, Menu, Button, Avatar, Dropdown, Drawer, Grid } from 'antd';
import {
@@ -123,6 +123,8 @@ const allMenuItems: MenuItemType[] = [
const MainLayout: React.FC = () => {
const [collapsed, setCollapsed] = useState(false);
const [drawerOpen, setDrawerOpen] = useState(false);
const [openKeys, setOpenKeys] = useState<string[]>([]);
const prevPathname = useRef('');
const navigate = useNavigate();
const location = useLocation();
const user = useMemo(() => JSON.parse(localStorage.getItem('user') || '{}'), []);
@@ -185,7 +187,20 @@ const MainLayout: React.FC = () => {
};
const selectedKeys = useMemo(() => findSelectedKeys(menuItems, location.pathname), [menuItems, location.pathname]);
const openKeys = useMemo(() => findOpenKeys(menuItems, location.pathname), [menuItems, location.pathname]);
// 路径变化时同步展开的菜单(不干扰用户手动展开/收起)
useEffect(() => {
if (location.pathname !== prevPathname.current) {
prevPathname.current = location.pathname;
setOpenKeys(findOpenKeys(menuItems, location.pathname));
}
}, [location.pathname, menuItems]);
const handleOpenChange = useCallback((keys: string[]) => {
// 只保留最新打开的一个子菜单
const latestKey = keys[keys.length - 1];
setOpenKeys(latestKey ? [latestKey] : []);
}, []);
const transformToMenuItems = (items: MenuItemType[]): any[] => {
@@ -201,7 +216,8 @@ const MainLayout: React.FC = () => {
theme="light"
mode="inline"
selectedKeys={selectedKeys}
defaultOpenKeys={openKeys}
openKeys={openKeys}
onOpenChange={handleOpenChange}
items={transformToMenuItems(menuItems)}
onClick={({ key }) => handleMenuClick(key)}
style={{ border: 'none' }}