在 React 19 + Next.js 15 中实现混合布局(全屏/带侧边栏)的推荐方案如下:
方案一:基于文件约定的布局系统(Next.js 15 推荐)
1. 创建布局文件夹结构
app/
├── (fullscreen)/ # 全屏页面组
│ ├── login/
│ │ └── page.js
│ └── landing/
│ └── page.js
├── (with-sidebar)/ # 带侧边栏页面组
│ ├── dashboard/
│ │ └── page.js
│ └── settings/
│ └── page.js
├── layout.js # 根布局
└── template.js # 可复用的模板组件
2. 实现不同布局 (app/(fullscreen)/layout.js
)
// 全屏布局
export default function FullscreenLayout({ children }) {
return (
<html lang="en" className="h-full">
<body className="h-full">{children}</body>
</html>
);
}
3. 带侧边栏布局 (app/(with-sidebar)/layout.js
)
import Sidebar from '@/components/Sidebar';
import Header from '@/components/Header';
export default function SidebarLayout({ children }) {
return (
<div className="flex flex-col min-h-screen">
<Header />
<div className="flex flex-1">
<Sidebar />
<main className="flex-1 p-6">{children}</main>
</div>
</div>
);
}
4. 根布局 (app/layout.js
)
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
方案二:基于条件渲染的布局组件
1. 创建动态布局组件
// components/LayoutSwitcher.js
'use client';
import { usePathname } from 'next/navigation';
import SidebarLayout from './SidebarLayout';
import FullscreenLayout from './FullscreenLayout';
export default function LayoutSwitcher({ children }) {
const pathname = usePathname();
const fullscreenPaths = ['/login', '/landing'];
return fullscreenPaths.includes(pathname) ? (
<FullscreenLayout>{children}</FullscreenLayout>
) : (
<SidebarLayout>{children}</SidebarLayout>
);
}
2. 修改根布局
// app/layout.js
import LayoutSwitcher from '@/components/LayoutSwitcher';
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<LayoutSwitcher>{children}</LayoutSwitcher>
</body>
</html>
);
}
方案三:使用 React 19 的元数据控制
1. 在页面中定义布局类型
// app/dashboard/page.js
export const layout = 'with-sidebar'; // 自定义元数据
export default function Dashboard() {
return <div>Dashboard Content</div>;
}
2. 创建布局包装器
// app/LayoutWrapper.js
import { getPageLayout } from './getLayout';
export default function LayoutWrapper({ children, layoutType }) {
const Layout = getPageLayout(layoutType);
return <Layout>{children}</Layout>;
}
最佳实践建议
CSS 处理:
/* globals.css */ .fullscreen-page { @apply h-screen w-screen overflow-hidden; } .sidebar-layout { @apply flex min-h-screen; }
性能优化:
- 使用
React.cache()
记忆化布局组件 - 对侧边栏使用
React.Suspense
延迟加载
- 使用
TypeScript 支持:
// types/layout.d.ts type LayoutType = 'fullscreen' | 'with-sidebar'; declare module '*.page.js' { export const layout?: LayoutType; }
状态共享:
// 使用 React 19 Actions 处理布局状态 const [layout, setLayout] = useActionState( (prev, newLayout) => newLayout, 'with-sidebar' );
对比总结
方案 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
文件约定 | 原生支持,清晰隔离 | 需要目录重组 | 新项目 |
条件渲染 | 灵活控制 | 需要客户端渲染 | 已有项目改造 |
元数据 | 声明式配置 | 需要自定义逻辑 | 中型项目 |
选择方案一时,Next.js 15 的路由组功能可以保持URL路径不变((fullscreen)/login
实际访问路径仍是 /login
)