You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js App Router下如何在/user与/tutor路由间共享页面?

Next.js App Router 共享同路径前缀下的页面方案

方案一:抽离公共组件到非路由目录

这是最直接的方案,将共享的仪表盘逻辑封装成独立组件,在两个路由的page.tsx中引入并传递差异化参数。

调整后的项目结构

/app
  /_components  # 下划线开头的目录不会被解析为路由
    Dashboard.tsx  # 共享的仪表盘核心组件
  /user
    /dashboard
      page.tsx
    /route2
      page.tsx
  /tutor
    /dashboard
      page.tsx
    /route3
      page.tsx

实现步骤

  1. 将原/user/dashboard/page.tsx和/tutor/dashboard/page.tsx中的共享逻辑迁移到Dashboard.tsx,通过props接收差异化配置:
// app/_components/Dashboard.tsx
interface DashboardProps {
  role: 'user' | 'tutor';
  // 可添加其他差异化参数,如数据、权限列表等
}

export default function Dashboard({ role }: DashboardProps) {
  return (
    <div className="dashboard">
      <h1>{role === 'user' ? '用户仪表盘' : '导师仪表盘'}</h1>
      {/* 放置所有共享的UI和逻辑 */}
      {role === 'user' && <div>用户专属功能区</div>}
      {role === 'tutor' && <div>导师专属功能区</div>}
    </div>
  );
}
  1. 在两个路由的page.tsx中导入并使用该组件:
// app/user/dashboard/page.tsx
import Dashboard from '@/app/_components/Dashboard';

export default function UserDashboard() {
  return <Dashboard role="user" />;
}
// app/tutor/dashboard/page.tsx
import Dashboard from '@/app/_components/Dashboard';

export default function TutorDashboard() {
  return <Dashboard role="tutor" />;
}

优点

  • 逻辑清晰,维护成本低,修改共享逻辑只需改动Dashboard.tsx
  • 保留原有的路由结构,不会导致跳转路径混乱
  • 支持灵活的差异化配置,适合两个页面有少量差异的场景

方案二:动态路由+中间件控制

如果需要支持更多角色类型,或者希望彻底避免重复的page.tsx文件,可以使用动态路由结合中间件来实现。

调整后的项目结构

/app
  /user
    /route2
      page.tsx
  /tutor
    /route3
      page.tsx
  /[role]  # 动态路由段,匹配user/tutor
    /dashboard
      page.tsx
  middleware.ts  # 中间件用于验证合法角色

实现步骤

  1. 创建动态路由的仪表盘页面,通过useParams获取当前角色:
// app/[role]/dashboard/page.tsx
import { useParams } from 'next/navigation';

export default function Dashboard() {
  const params = useParams();
  const role = params.role as 'user' | 'tutor';

  // 根据角色请求对应数据或渲染差异化内容
  return (
    <div>
      <h1>{role === 'user' ? '用户仪表盘' : '导师仪表盘'}</h1>
      {/* 共享的仪表盘逻辑 */}
    </div>
  );
}
  1. 编写中间件验证角色合法性,防止非法路径访问:
// app/middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  const role = request.nextUrl.pathname.split('/')[1];
  // 只允许user和tutor角色访问该路由
  if (!['user', 'tutor'].includes(role)) {
    return NextResponse.redirect(new URL('/404', request.url));
  }
  return NextResponse.next();
}

// 指定中间件匹配的路由规则
export const config = {
  matcher: '/:role/dashboard',
};

优点

  • 只需维护一个仪表盘页面文件,适合多角色共享路由的场景
  • 保留原有的/user/dashboard和/tutor/dashboard路径
  • 中间件统一控制权限,避免非法访问

方案三:复用服务端逻辑(针对Server Components)

如果你的页面是Server Components,可以将共享的服务端数据获取逻辑抽离到独立文件,进一步减少重复代码。

实现步骤

  1. 创建共享的服务端逻辑文件:
// app/_lib/dashboard-service.ts
export async function getDashboardData(role: 'user' | 'tutor', userId: string) {
  // 根据角色获取对应的数据
  if (role === 'user') {
    const res = await fetch(`/api/user/dashboard/${userId}`);
    return res.json();
  } else {
    const res = await fetch(`/api/tutor/dashboard/${userId}`);
    return res.json();
  }
}
  1. 在两个路由的page.tsx中复用该逻辑:
// app/user/dashboard/page.tsx
import Dashboard from '@/app/_components/Dashboard';
import { getDashboardData } from '@/app/_lib/dashboard-service';
import { getCurrentUser } from '@/app/_lib/auth';

export default async function UserDashboard() {
  const user = await getCurrentUser();
  const data = await getDashboardData('user', user.id);
  return <Dashboard role="user" data={data} />;
}

优点

  • 服务端数据逻辑复用,避免重复编写API请求代码
  • 结合方案一使用,实现UI和数据逻辑的双重复用

内容的提问来源于stack exchange,提问作者Miriam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 07:05:05