Next.js App Router:如何将page.tsx的props传递给Layout.tsx?
实现路由角色对应的动态侧边栏方案
针对你遇到的「各角色页面定义的sidebarItems无法传递给DashboardLayout」的问题,以下是三种可行的实现方案,适配Next.js App Router(结合你提到的page.tsx结构):
方案一:React Context 传递侧边栏配置
通过创建全局Context,让每个角色页面提供对应的侧边栏数据,再在Layout中消费该数据,适合侧边栏与页面强关联的场景。
步骤1:创建侧边栏Context
// app/dashboard/context/SidebarContext.tsx 'use client'; import { createContext, useContext, ReactNode } from 'react'; // 定义侧边栏项类型 export type SidebarItem = { label: string; href: string; icon?: ReactNode; }; type SidebarContextType = { sidebarItems: SidebarItem[]; }; const SidebarContext = createContext<SidebarContextType | undefined>(undefined); export function SidebarProvider({ children, sidebarItems }: { children: ReactNode; sidebarItems: SidebarItem[] }) { return ( <SidebarContext.Provider value={{ sidebarItems }}> {children} </SidebarContext.Provider> ); } export function useSidebar() { const context = useContext(SidebarContext); if (!context) { throw new Error('useSidebar 必须在 SidebarProvider 内部使用'); } return context; }
步骤2:在角色页面中提供配置
// app/dashboard/admin/page.tsx import { SidebarProvider, SidebarItem } from '../context/SidebarContext'; // Admin 角色的侧边栏配置 const adminSidebarItems: SidebarItem[] = [ { label: '用户管理', href: '/dashboard/admin/users' }, { label: '角色配置', href: '/dashboard/admin/roles' }, { label: '系统日志', href: '/dashboard/admin/logs' }, ]; export default function AdminPage() { return ( <SidebarProvider sidebarItems={adminSidebarItems}> <h1>管理员仪表盘</h1> {/* 页面其他内容 */} </SidebarProvider> ); }
步骤3:在DashboardLayout中消费数据
// app/dashboard/layout.tsx 'use client'; import { useSidebar } from './context/SidebarContext'; export default function DashboardLayout({ children }: { children: ReactNode }) { const { sidebarItems } = useSidebar(); return ( <div className="flex h-screen"> {/* 动态侧边栏 */} <aside className="w-64 bg-gray-100 border-r"> <nav className="p-4"> {sidebarItems.map((item, idx) => ( <a key={idx} href={item.href} className="block py-2 px-3 rounded hover:bg-gray-200 mb-1" > {item.label} </a> ))} </nav> </aside> {/* 主内容区 */} <main className="flex-1 p-6 overflow-auto"> {children} </main> </div> ); }
方案二:利用路由元数据(Next.js App Router)
Next.js App Router允许在page.tsx中自定义扩展元数据,通过路由路径匹配对应的元数据,无需额外Context。
步骤1:在角色页面定义元数据
// app/dashboard/company/page.tsx import type { SidebarItem } from '../types'; // 自定义元数据,包含侧边栏配置 export const metadata = { sidebarItems: [ { label: '企业信息', href: '/dashboard/company/profile' }, { label: '职位发布', href: '/dashboard/company/jobs' }, { label: '简历管理', href: '/dashboard/company/resumes' }, ] as SidebarItem[], }; export default function CompanyPage() { return <h1>企业仪表盘</h1>; }
步骤2:在Layout中匹配路由元数据
// app/dashboard/layout.tsx 'use client'; import { usePathname } from 'next/navigation'; import { metadata as adminMeta } from './admin/page'; import { metadata as companyMeta } from './company/page'; import { metadata as studentMeta } from './student/page'; import type { SidebarItem } from './types'; // 建立路由与元数据的映射 const routeMetaMap: Record<string, { sidebarItems: SidebarItem[] }> = { '/dashboard/admin': adminMeta, '/dashboard/company': companyMeta, '/dashboard/student': studentMeta, }; export default function DashboardLayout({ children }: { children: ReactNode }) { const pathname = usePathname(); // 匹配当前路由对应的元数据(支持子路由继承父路由配置) const matchedRoute = Object.keys(routeMetaMap).find(route => pathname.startsWith(route) ) || '/dashboard/admin'; const { sidebarItems } = routeMetaMap[matchedRoute]; return ( <div className="flex h-screen"> <aside className="w-64 bg-gray-100 border-r"> <nav className="p-4"> {sidebarItems.map((item, idx) => ( <a key={idx} href={item.href} className="block py-2 px-3 rounded hover:bg-gray-200 mb-1" > {item.label} </a> ))} </nav> </aside> <main className="flex-1 p-6 overflow-auto"> {children} </main> </div> ); }
方案三:基于RBAC角色直接生成侧边栏
如果侧边栏完全由用户角色决定,无需和页面绑定,可以直接在Layout中根据当前用户角色读取预设的侧边栏配置,逻辑更简洁。
// app/dashboard/layout.tsx 'use client'; import { useUser } from './hooks/useUser'; // 自定义hook,获取当前用户角色 import type { SidebarItem } from './types'; // 按角色预设侧边栏配置 const roleSidebarConfig: Record<string, SidebarItem[]> = { admin: [ { label: '用户管理', href: '/dashboard/admin/users' }, { label: '角色配置', href: '/dashboard/admin/roles' }, ], company: [ { label: '企业信息', href: '/dashboard/company/profile' }, { label: '职位管理', href: '/dashboard/company/jobs' }, ], student: [ { label: '我的简历', href: '/dashboard/student/resume' }, { label: '申请记录', href: '/dashboard/student/applications' }, ], }; export default function DashboardLayout({ children }: { children: ReactNode }) { const { user } = useUser(); // 根据用户角色获取对应侧边栏,默认空数组 const sidebarItems = roleSidebarConfig[user?.role || ''] || []; return ( <div className="flex h-screen"> <aside className="w-64 bg-gray-100 border-r"> <nav className="p-4"> {sidebarItems.map((item, idx) => ( <a key={idx} href={item.href} className="block py-2 px-3 rounded hover:bg-gray-200 mb-1" > {item.label} </a> ))} </nav> </aside> <main className="flex-1 p-6 overflow-auto"> {children} </main> </div> ); }
方案选型建议
- Context方案:适合同角色不同页面需要展示不同侧边栏的场景,灵活度最高。
- 路由元数据方案:适合Next.js环境,配置与页面耦合度低,无需额外状态管理。
- RBAC角色映射方案:适合侧边栏完全由角色决定的场景,代码最简洁,维护成本低。
内容的提问来源于stack exchange,提问作者Anish Shobith P S
相关产品推荐
相关产品推荐

