在 Next.js 中保持二級菜單刷新后展開狀態的解決方案
在 Next.js 應用中,當頁面刷新時保持二級菜單的展開狀態,可以通過以下幾種方法實現:
方法1:使用 URL 參數保存狀態(推薦)
import { useRouter } from 'next/router';
import { useEffect, useState } from 'react';const MenuComponent = () => {const router = useRouter();const { query } = router;const [expandedMenu, setExpandedMenu] = useState<string | null>(null);// 從URL參數初始化菜單狀態useEffect(() => {if (query.expandedMenu) {setExpandedMenu(query.expandedMenu as string);}}, [query.expandedMenu]);const toggleMenu = (menuId: string) => {const newState = expandedMenu === menuId ? null : menuId;setExpandedMenu(newState);// 更新URL但不觸發頁面刷新router.push({pathname: router.pathname,query: { ...query, expandedMenu: newState }}, undefined, { shallow: true });};return (<div><div onClick={() => toggleMenu('menu1')}>主菜單1</div>{expandedMenu === 'menu1' && (<div className="submenu"><div>子菜單1</div><div>子菜單2</div></div>)}</div>);
};
方法2:使用 localStorage 保存狀態
import { useEffect, useState } from 'react';const MenuComponent = () => {const [expandedMenu, setExpandedMenu] = useState<string | null>(null);// 從localStorage初始化菜單狀態useEffect(() => {const savedState = typeof window !== 'undefined' ? localStorage.getItem('expandedMenu') : null;if (savedState) {setExpandedMenu(savedState);}}, []);const toggleMenu = (menuId: string) => {const newState = expandedMenu === menuId ? null : menuId;setExpandedMenu(newState);localStorage.setItem('expandedMenu', newState || '');};// 渲染邏輯同上
};
方法3:使用狀態管理庫(如 Zustand)
// store/menuStore.ts
import create from 'zustand';
import { persist } from 'zustand/middleware';interface MenuState {expandedMenu: string | null;toggleMenu: (menuId: string) => void;
}export const useMenuStore = create<MenuState>()(persist((set) => ({expandedMenu: null,toggleMenu: (menuId) => set((state) => ({expandedMenu: state.expandedMenu === menuId ? null : menuId})),}),{name: 'menu-storage', // localStorage的key})
);// 組件中使用
const MenuComponent = () => {const { expandedMenu, toggleMenu } = useMenuStore();// 渲染邏輯
};
方法4:使用 Cookie(服務端可獲取)
import { useState } from 'react';
import { setCookie, parseCookies } from 'nookies';export const getServerSideProps = (ctx) => {const cookies = parseCookies(ctx);return {props: {initialExpandedMenu: cookies.expandedMenu || null}};
};const MenuComponent = ({ initialExpandedMenu }) => {const [expandedMenu, setExpandedMenu] = useState(initialExpandedMenu);const toggleMenu = (menuId: string) => {const newState = expandedMenu === menuId ? null : menuId;setExpandedMenu(newState);setCookie(null, 'expandedMenu', newState || '', {path: '/',maxAge: 30 * 24 * 60 * 60, // 30天});};// 渲染邏輯
};
最佳實踐建議
- 簡單場景:使用 URL 參數方法(方法1),既保持狀態又方便分享鏈接
- 復雜應用:使用 Zustand 等狀態管理庫(方法3),特別是需要跨組件共享狀態時
- SEO相關:如果菜單狀態影響內容展示,考慮服務端方案(方法4)
- 用戶體驗:添加過渡動畫使菜單展開/收起更平滑
注意事項
- 服務端渲染兼容性:在 useEffect 中訪問 localStorage/window 等客戶端 API
- 狀態同步:確保 URL、存儲和組件狀態保持一致
- 安全考慮:不要用這些方法存儲敏感信息
- 性能優化:對于大型菜單,考慮虛擬滾動等技術
以上方法都可以在 Next.js 應用中有效保持二級菜單的展開狀態,即使在頁面刷新后也能恢復之前的狀態。