Skip to content

路由配置与嵌套路由

概述

React Router v6的嵌套路由是构建复杂单页应用的核心特性。它允许创建层次化的路由结构,实现布局共享和模块化的路由管理。本文深入探讨路由配置方法和嵌套路由的各种使用模式。

路由配置方式

1. JSX配置方式

最直观的路由配置方式,适合简单到中等复杂度的应用:

jsx
import { BrowserRouter, Routes, Route } from 'react-router-dom';

function App() {
  return (
    <BrowserRouter>
      <Routes>
        {/* 根路由 */}
        <Route path="/" element={<Layout />}>
          {/* 嵌套路由 */}
          <Route index element={<Home />} />
          <Route path="about" element={<About />} />
          <Route path="contact" element={<Contact />} />
          
          {/* 用户相关路由 */}
          <Route path="users" element={<UsersLayout />}>
            <Route index element={<UsersList />} />
            <Route path=":id" element={<UserProfile />} />
            <Route path=":id/edit" element={<EditUser />} />
            <Route path="new" element={<CreateUser />} />
          </Route>
          
          {/* 产品相关路由 */}
          <Route path="products" element={<ProductsLayout />}>
            <Route index element={<ProductsList />} />
            <Route path="category/:category" element={<CategoryProducts />} />
            <Route path=":id" element={<ProductDetail />} />
            <Route path=":id/reviews" element={<ProductReviews />} />
          </Route>
        </Route>
        
        {/* 认证路由(独立布局) */}
        <Route path="auth" element={<AuthLayout />}>
          <Route path="login" element={<Login />} />
          <Route path="register" element={<Register />} />
          <Route path="forgot-password" element={<ForgotPassword />} />
        </Route>
        
        {/* 404路由 */}
        <Route path="*" element={<NotFound />} />
      </Routes>
    </BrowserRouter>
  );
}

2. 对象配置方式

使用createBrowserRouter进行配置,适合大型复杂应用:

jsx
import { createBrowserRouter, RouterProvider } from 'react-router-dom';

const router = createBrowserRouter([
  {
    path: '/',
    element: <RootLayout />,
    errorElement: <RootErrorBoundary />,
    children: [
      {
        index: true,
        element: <HomePage />
      },
      {
        path: 'dashboard',
        element: <DashboardLayout />,
        children: [
          {
            index: true,
            element: <DashboardHome />
          },
          {
            path: 'analytics',
            element: <Analytics />,
            loader: analyticsLoader
          },
          {
            path: 'reports',
            element: <Reports />
          }
        ]
      },
      {
        path: 'users',
        element: <UsersLayout />,
        children: [
          {
            index: true,
            element: <UsersList />,
            loader: usersListLoader
          },
          {
            path: ':userId',
            element: <UserDetail />,
            loader: ({ params }) => userDetailLoader(params.userId),
            children: [
              {
                index: true,
                element: <UserOverview />
              },
              {
                path: 'posts',
                element: <UserPosts />,
                loader: ({ params }) => userPostsLoader(params.userId)
              },
              {
                path: 'settings',
                element: <UserSettings />
              }
            ]
          }
        ]
      }
    ]
  },
  {
    path: '/admin',
    element: <AdminLayout />,
    errorElement: <AdminErrorBoundary />,
    children: [
      // 管理员路由配置
    ]
  }
]);

function App() {
  return <RouterProvider router={router} />;
}

3. 动态路由配置

根据用户权限或配置动态生成路由:

jsx
import { createBrowserRouter } from 'react-router-dom';

// 路由配置生成函数
function createAppRouter(user, permissions, features) {
  const baseRoutes = [
    {
      path: '/',
      element: <Layout />,
      children: [
        { index: true, element: <Home /> },
        { path: 'profile', element: <Profile /> }
      ]
    }
  ];

  // 根据权限添加路由
  if (permissions.includes('read:users')) {
    baseRoutes[0].children.push({
      path: 'users',
      element: <UsersLayout />,
      children: [
        { index: true, element: <UsersList /> },
        { path: ':id', element: <UserDetail /> }
      ]
    });

    // 用户管理权限
    if (permissions.includes('write:users')) {
      baseRoutes[0].children
        .find(route => route.path === 'users')
        .children.push(
          { path: ':id/edit', element: <EditUser /> },
          { path: 'new', element: <CreateUser /> }
        );
    }
  }

  // 根据功能开关添加路由
  if (features.analyticsEnabled) {
    baseRoutes[0].children.push({
      path: 'analytics',
      element: <Analytics />
    });
  }

  // 管理员路由
  if (user.role === 'admin') {
    baseRoutes.push({
      path: '/admin',
      element: <AdminLayout />,
      children: [
        { index: true, element: <AdminDashboard /> },
        { path: 'users', element: <AdminUsers /> },
        { path: 'settings', element: <AdminSettings /> }
      ]
    });
  }

  return createBrowserRouter(baseRoutes);
}

// 使用
function App() {
  const { user, permissions, features } = useAuth();
  const router = useMemo(
    () => createAppRouter(user, permissions, features),
    [user, permissions, features]
  );

  return <RouterProvider router={router} />;
}

嵌套路由详解

1. Outlet组件

Outlet是嵌套路由的核心,用于渲染匹配的子路由:

jsx
import { Outlet, Link, useLocation } from 'react-router-dom';

function DashboardLayout() {
  const location = useLocation();

  return (
    <div className="dashboard-layout">
      {/* 侧边栏导航 */}
      <aside className="sidebar">
        <nav>
          <Link 
            to="/dashboard" 
            className={location.pathname === '/dashboard' ? 'active' : ''}
          >
            Overview
          </Link>
          <Link 
            to="/dashboard/analytics"
            className={location.pathname === '/dashboard/analytics' ? 'active' : ''}
          >
            Analytics
          </Link>
          <Link 
            to="/dashboard/reports"
            className={location.pathname === '/dashboard/reports' ? 'active' : ''}
          >
            Reports
          </Link>
          <Link 
            to="/dashboard/settings"
            className={location.pathname === '/dashboard/settings' ? 'active' : ''}
          >
            Settings
          </Link>
        </nav>
      </aside>

      {/* 主要内容区域 */}
      <main className="main-content">
        <header className="content-header">
          <h1>Dashboard</h1>
          <BreadcrumbNav />
        </header>

        {/* 子路由在这里渲染 */}
        <div className="content-body">
          <Outlet />
        </div>
      </main>
    </div>
  );
}

// 面包屑导航
function BreadcrumbNav() {
  const location = useLocation();
  
  const generateBreadcrumbs = () => {
    const pathSegments = location.pathname.split('/').filter(Boolean);
    const breadcrumbs = [];
    
    let currentPath = '';
    pathSegments.forEach((segment, index) => {
      currentPath += `/${segment}`;
      
      // 路径映射到显示名称
      const displayNames = {
        dashboard: 'Dashboard',
        analytics: 'Analytics',
        reports: 'Reports',
        settings: 'Settings'
      };
      
      breadcrumbs.push({
        path: currentPath,
        name: displayNames[segment] || segment.charAt(0).toUpperCase() + segment.slice(1),
        isLast: index === pathSegments.length - 1
      });
    });
    
    return breadcrumbs;
  };

  const breadcrumbs = generateBreadcrumbs();

  return (
    <nav className="breadcrumb">
      <Link to="/">Home</Link>
      {breadcrumbs.map(crumb => (
        <span key={crumb.path}>
          <span className="separator"> / </span>
          {crumb.isLast ? (
            <span className="current">{crumb.name}</span>
          ) : (
            <Link to={crumb.path}>{crumb.name}</Link>
          )}
        </span>
      ))}
    </nav>
  );
}

2. Index路由

Index路由渲染在父路由的确切路径上:

jsx
function App() {
  return (
    <Routes>
      <Route path="/" element={<Layout />}>
        {/* index路由匹配父路由的确切路径 */}
        <Route index element={<Home />} /> {/* 匹配 "/" */}
        
        <Route path="users" element={<UsersLayout />}>
          <Route index element={<UsersList />} /> {/* 匹配 "/users" */}
          <Route path=":id" element={<UserDetail />} /> {/* 匹配 "/users/123" */}
        </Route>
        
        <Route path="products" element={<ProductsLayout />}>
          <Route index element={<ProductsList />} /> {/* 匹配 "/products" */}
          <Route path="featured" element={<FeaturedProducts />} /> {/* 匹配 "/products/featured" */}
          <Route path=":id" element={<ProductDetail />} /> {/* 匹配 "/products/123" */}
        </Route>
      </Route>
    </Routes>
  );
}

// 使用index路由实现默认标签页
function UserProfile() {
  const { id } = useParams();

  return (
    <div className="user-profile">
      <div className="profile-header">
        <h1>User Profile</h1>
        <nav className="profile-tabs">
          <Link to={`/users/${id}`}>Overview</Link>
          <Link to={`/users/${id}/posts`}>Posts</Link>
          <Link to={`/users/${id}/followers`}>Followers</Link>
          <Link to={`/users/${id}/settings`}>Settings</Link>
        </nav>
      </div>

      <div className="profile-content">
        <Outlet />
      </div>
    </div>
  );
}

// 路由配置
<Route path="users/:id" element={<UserProfile />}>
  <Route index element={<UserOverview />} /> {/* 默认显示概览 */}
  <Route path="posts" element={<UserPosts />} />
  <Route path="followers" element={<UserFollowers />} />
  <Route path="settings" element={<UserSettings />} />
</Route>

3. 相对路由

jsx
// 相对路径导航
function ProductsLayout() {
  return (
    <div className="products-layout">
      <nav className="products-nav">
        {/* 相对路径链接 */}
        <Link to="." end>All Products</Link> {/* 当前路径 */}
        <Link to="featured">Featured</Link> {/* 相对于当前路径 */}
        <Link to="on-sale">On Sale</Link>
        <Link to="../categories">Categories</Link> {/* 上级路径 */}
      </nav>

      <div className="products-content">
        <Outlet />
      </div>
    </div>
  );
}

// 编程式相对导航
function ProductCard({ product }) {
  const navigate = useNavigate();

  const handleViewDetails = () => {
    navigate(product.id.toString()); // 相对导航到详情页
  };

  const handleEdit = () => {
    navigate(`${product.id}/edit`); // 相对导航到编辑页
  };

  const handleBackToCategory = () => {
    navigate(`../category/${product.category}`); // 导航到分类页
  };

  return (
    <div className="product-card">
      <h3>{product.name}</h3>
      <p>${product.price}</p>
      
      <div className="product-actions">
        <button onClick={handleViewDetails}>View Details</button>
        <button onClick={handleEdit}>Edit</button>
        <button onClick={handleBackToCategory}>View Category</button>
      </div>
    </div>
  );
}

复杂嵌套路由案例

案例1:电商管理后台

jsx
import { Routes, Route, Outlet } from 'react-router-dom';

function EcommerceAdmin() {
  return (
    <Routes>
      <Route path="/" element={<AdminLayout />}>
        {/* 仪表板 */}
        <Route index element={<Dashboard />} />
        
        {/* 产品管理 */}
        <Route path="products" element={<ProductsManagement />}>
          <Route index element={<ProductsList />} />
          <Route path="categories" element={<CategoriesManagement />}>
            <Route index element={<CategoriesList />} />
            <Route path=":categoryId" element={<CategoryDetail />} />
            <Route path=":categoryId/edit" element={<EditCategory />} />
            <Route path="new" element={<CreateCategory />} />
          </Route>
          <Route path="inventory" element={<InventoryManagement />}>
            <Route index element={<InventoryOverview />} />
            <Route path="low-stock" element={<LowStockProducts />} />
            <Route path="transfers" element={<InventoryTransfers />} />
          </Route>
          <Route path=":productId" element={<ProductDetail />}>
            <Route index element={<ProductOverview />} />
            <Route path="variants" element={<ProductVariants />} />
            <Route path="images" element={<ProductImages />} />
            <Route path="seo" element={<ProductSEO />} />
            <Route path="inventory" element={<ProductInventory />} />
          </Route>
          <Route path=":productId/edit" element={<EditProduct />} />
          <Route path="new" element={<CreateProduct />} />
        </Route>
        
        {/* 订单管理 */}
        <Route path="orders" element={<OrdersManagement />}>
          <Route index element={<OrdersList />} />
          <Route path="pending" element={<PendingOrders />} />
          <Route path="processing" element={<ProcessingOrders />} />
          <Route path="shipped" element={<ShippedOrders />} />
          <Route path="returns" element={<Returns />} />
          <Route path=":orderId" element={<OrderDetail />}>
            <Route index element={<OrderOverview />} />
            <Route path="items" element={<OrderItems />} />
            <Route path="shipping" element={<OrderShipping />} />
            <Route path="history" element={<OrderHistory />} />
          </Route>
        </Route>
        
        {/* 客户管理 */}
        <Route path="customers" element={<CustomersManagement />}>
          <Route index element={<CustomersList />} />
          <Route path="segments" element={<CustomerSegments />} />
          <Route path=":customerId" element={<CustomerDetail />}>
            <Route index element={<CustomerProfile />} />
            <Route path="orders" element={<CustomerOrders />} />
            <Route path="support" element={<CustomerSupport />} />
          </Route>
        </Route>
        
        {/* 营销管理 */}
        <Route path="marketing" element={<MarketingLayout />}>
          <Route index element={<MarketingDashboard />} />
          <Route path="campaigns" element={<CampaignsManagement />}>
            <Route index element={<CampaignsList />} />
            <Route path=":campaignId" element={<CampaignDetail />} />
            <Route path="new" element={<CreateCampaign />} />
          </Route>
          <Route path="discounts" element={<DiscountsManagement />}>
            <Route index element={<DiscountsList />} />
            <Route path=":discountId" element={<DiscountDetail />} />
            <Route path="new" element={<CreateDiscount />} />
          </Route>
          <Route path="email" element={<EmailMarketing />}>
            <Route index element={<EmailCampaigns />} />
            <Route path="templates" element={<EmailTemplates />} />
            <Route path="subscribers" element={<EmailSubscribers />} />
          </Route>
        </Route>
        
        {/* 设置 */}
        <Route path="settings" element={<SettingsLayout />}>
          <Route index element={<GeneralSettings />} />
          <Route path="store" element={<StoreSettings />} />
          <Route path="payments" element={<PaymentSettings />} />
          <Route path="shipping" element={<ShippingSettings />} />
          <Route path="taxes" element={<TaxSettings />} />
          <Route path="users" element={<UserManagement />} />
        </Route>
      </Route>
      
      {/* 认证页面(无布局) */}
      <Route path="/login" element={<AdminLogin />} />
      <Route path="*" element={<AdminNotFound />} />
    </Routes>
  );
}

// 布局组件
function AdminLayout() {
  const location = useLocation();

  return (
    <div className="admin-layout">
      <Sidebar currentPath={location.pathname} />
      
      <div className="admin-main">
        <Header />
        
        <div className="admin-content">
          <Outlet />
        </div>
      </div>
    </div>
  );
}

function ProductsManagement() {
  return (
    <div className="products-management">
      <div className="management-header">
        <h2>Products Management</h2>
        <div className="header-actions">
          <Link to="new" className="btn btn-primary">Add Product</Link>
          <Link to="categories" className="btn">Manage Categories</Link>
          <Link to="inventory" className="btn">Inventory</Link>
        </div>
      </div>

      <div className="management-content">
        <Outlet />
      </div>
    </div>
  );
}

function ProductDetail() {
  const { productId } = useParams();
  const [product, setProduct] = useState(null);

  useEffect(() => {
    fetchProduct(productId).then(setProduct);
  }, [productId]);

  if (!product) return <div>Loading...</div>;

  return (
    <div className="product-detail">
      <div className="product-header">
        <h2>{product.name}</h2>
        <div className="product-tabs">
          <Link to={`/products/${productId}`} end>Overview</Link>
          <Link to={`/products/${productId}/variants`}>Variants</Link>
          <Link to={`/products/${productId}/images`}>Images</Link>
          <Link to={`/products/${productId}/seo`}>SEO</Link>
          <Link to={`/products/${productId}/inventory`}>Inventory</Link>
        </div>
      </div>

      <div className="product-content">
        <Outlet context={{ product, setProduct }} />
      </div>
    </div>
  );
}

案例2:学习管理系统

jsx
function LearningPlatform() {
  return (
    <Routes>
      <Route path="/" element={<PlatformLayout />}>
        {/* 首页 */}
        <Route index element={<HomePage />} />
        
        {/* 课程相关 */}
        <Route path="courses" element={<CoursesLayout />}>
          <Route index element={<CoursesCatalog />} />
          <Route path="categories/:category" element={<CategoryCourses />} />
          <Route path="search" element={<CoursesSearch />} />
          <Route path=":courseId" element={<CourseDetail />}>
            <Route index element={<CourseOverview />} />
            <Route path="curriculum" element={<CourseCurriculum />} />
            <Route path="reviews" element={<CourseReviews />} />
            <Route path="instructor" element={<CourseInstructor />} />
          </Route>
        </Route>
        
        {/* 学习路径 */}
        <Route path="learning-paths" element={<LearningPathsLayout />}>
          <Route index element={<LearningPathsList />} />
          <Route path=":pathId" element={<LearningPathDetail />}>
            <Route index element={<PathOverview />} />
            <Route path="courses" element={<PathCourses />} />
            <Route path="progress" element={<PathProgress />} />
          </Route>
        </Route>
        
        {/* 我的学习 */}
        <Route path="my-learning" element={<MyLearningLayout />}>
          <Route index element={<MyLearningDashboard />} />
          <Route path="enrolled" element={<EnrolledCourses />} />
          <Route path="completed" element={<CompletedCourses />} />
          <Route path="wishlist" element={<Wishlist />} />
          <Route path="certificates" element={<Certificates />} />
          <Route path="progress" element={<LearningProgress />} />
        </Route>
        
        {/* 课程学习界面 */}
        <Route path="learn/:courseId" element={<LearningInterface />}>
          <Route path="lesson/:lessonId" element={<LessonPlayer />} />
          <Route path="quiz/:quizId" element={<Quiz />} />
          <Route path="assignment/:assignmentId" element={<Assignment />} />
          <Route path="discussion/:topicId?" element={<Discussion />} />
        </Route>
        
        {/* 用户相关 */}
        <Route path="profile" element={<ProfileLayout />}>
          <Route index element={<ProfileOverview />} />
          <Route path="edit" element={<EditProfile />} />
          <Route path="achievements" element={<Achievements />} />
          <Route path="activity" element={<ActivityHistory />} />
        </Route>
      </Route>
      
      {/* 认证页面 */}
      <Route path="/auth" element={<AuthLayout />}>
        <Route path="login" element={<Login />} />
        <Route path="register" element={<Register />} />
        <Route path="verify-email" element={<VerifyEmail />} />
      </Route>
      
      {/* 讲师管理 */}
      <Route path="/instructor" element={<InstructorLayout />}>
        <Route index element={<InstructorDashboard />} />
        <Route path="courses" element={<InstructorCourses />}>
          <Route index element={<CoursesList />} />
          <Route path=":courseId" element={<ManageCourse />}>
            <Route index element={<CourseSettings />} />
            <Route path="content" element={<CourseContent />} />
            <Route path="students" element={<CourseStudents />} />
            <Route path="analytics" element={<CourseAnalytics />} />
          </Route>
          <Route path="new" element={<CreateCourse />} />
        </Route>
      </Route>
    </Routes>
  );
}

// 学习界面布局 - 全屏模式
function LearningInterface() {
  const { courseId } = useParams();
  const location = useLocation();
  const [course, setCourse] = useState(null);
  const [sidebarOpen, setSidebarOpen] = useState(true);

  useEffect(() => {
    fetchCourse(courseId).then(setCourse);
  }, [courseId]);

  if (!course) return <div>Loading course...</div>;

  return (
    <div className="learning-interface">
      {/* 顶部导航条 */}
      <header className="learning-header">
        <div className="course-info">
          <Link to={`/courses/${courseId}`} className="course-title">
            {course.title}
          </Link>
          <span className="lesson-progress">
            Lesson 3 of 12
          </span>
        </div>

        <div className="learning-controls">
          <button onClick={() => setSidebarOpen(!sidebarOpen)}>
            Toggle Menu
          </button>
          <Link to="/my-learning">My Learning</Link>
        </div>
      </header>

      <div className="learning-body">
        {/* 侧边栏 - 课程内容导航 */}
        {sidebarOpen && (
          <aside className="course-sidebar">
            <nav className="course-navigation">
              <h3>Course Content</h3>
              {course.modules.map(module => (
                <div key={module.id} className="module">
                  <h4>{module.title}</h4>
                  <ul>
                    {module.lessons.map(lesson => (
                      <li key={lesson.id}>
                        <Link 
                          to={`lesson/${lesson.id}`}
                          className={location.pathname.includes(`lesson/${lesson.id}`) ? 'active' : ''}
                        >
                          {lesson.title}
                        </Link>
                      </li>
                    ))}
                    {module.quizzes.map(quiz => (
                      <li key={quiz.id}>
                        <Link to={`quiz/${quiz.id}`}>
                          Quiz: {quiz.title}
                        </Link>
                      </li>
                    ))}
                  </ul>
                </div>
              ))}
            </nav>
          </aside>
        )}

        {/* 主要学习内容 */}
        <main className="learning-main">
          <Outlet context={{ course, setCourse }} />
        </main>
      </div>
    </div>
  );
}

案例3:多租户应用

jsx
function MultiTenantApp() {
  return (
    <Routes>
      {/* 租户路由 */}
      <Route path="/tenant/:tenantId" element={<TenantLayout />}>
        <Route index element={<TenantDashboard />} />
        
        {/* 租户的用户管理 */}
        <Route path="users" element={<TenantUsersLayout />}>
          <Route index element={<TenantUsersList />} />
          <Route path="roles" element={<RolesManagement />} />
          <Route path="permissions" element={<PermissionsManagement />} />
          <Route path=":userId" element={<TenantUserDetail />}>
            <Route index element={<UserProfile />} />
            <Route path="permissions" element={<UserPermissions />} />
            <Route path="activity" element={<UserActivity />} />
          </Route>
        </Route>
        
        {/* 租户的应用设置 */}
        <Route path="settings" element={<TenantSettingsLayout />}>
          <Route index element={<GeneralSettings />} />
          <Route path="branding" element={<BrandingSettings />} />
          <Route path="integrations" element={<IntegrationsSettings />} />
          <Route path="billing" element={<BillingSettings />} />
        </Route>
      </Route>
      
      {/* 超级管理员路由 */}
      <Route path="/admin" element={<SuperAdminLayout />}>
        <Route index element={<SuperAdminDashboard />} />
        <Route path="tenants" element={<TenantsManagement />}>
          <Route index element={<TenantsList />} />
          <Route path=":tenantId" element={<TenantDetail />} />
          <Route path="new" element={<CreateTenant />} />
        </Route>
        <Route path="system" element={<SystemSettings />} />
      </Route>
    </Routes>
  );
}

function TenantLayout() {
  const { tenantId } = useParams();
  const [tenant, setTenant] = useState(null);
  
  useEffect(() => {
    fetchTenant(tenantId).then(setTenant);
  }, [tenantId]);

  if (!tenant) return <div>Loading tenant...</div>;

  return (
    <div className="tenant-layout" data-tenant={tenantId}>
      <header className="tenant-header">
        <div className="tenant-brand">
          <img src={tenant.logo} alt={tenant.name} />
          <h1>{tenant.name}</h1>
        </div>
        
        <nav className="tenant-nav">
          <Link to={`/tenant/${tenantId}`}>Dashboard</Link>
          <Link to={`/tenant/${tenantId}/users`}>Users</Link>
          <Link to={`/tenant/${tenantId}/settings`}>Settings</Link>
        </nav>
      </header>

      <main className="tenant-main">
        <Outlet context={{ tenant, setTenant }} />
      </main>
    </div>
  );
}

路由配置最佳实践

1. 路由结构设计

jsx
// 好的路由结构设计原则
const routeDesignPrinciples = {
  // 1. 层次清晰
  hierarchy: {
    good: '/admin/products/123/edit',
    explanation: '清晰的层次结构,便于理解'
  },
  
  // 2. 语义化
  semantic: {
    good: '/courses/javascript/lessons/variables',
    bad: '/c/js/l/var',
    explanation: '使用有意义的路径名称'
  },
  
  // 3. 一致性
  consistency: {
    good: ['/users/123', '/products/456', '/orders/789'],
    bad: ['/user/123', '/product-detail/456', '/order_info/789'],
    explanation: '保持命名和结构的一致性'
  },
  
  // 4. 可扩展性
  scalability: {
    good: {
      current: '/api/v1/users',
      future: '/api/v2/users'
    },
    explanation: '考虑未来的扩展需求'
  }
};

// 实际应用
const wellDesignedRoutes = [
  // 用户管理
  { path: '/users', name: 'Users List' },
  { path: '/users/:id', name: 'User Detail' },
  { path: '/users/:id/edit', name: 'Edit User' },
  { path: '/users/:id/orders', name: 'User Orders' },
  
  // 产品管理
  { path: '/products', name: 'Products List' },
  { path: '/products/categories/:category', name: 'Category Products' },
  { path: '/products/:id', name: 'Product Detail' },
  { path: '/products/:id/variants', name: 'Product Variants' },
  
  // 订单管理
  { path: '/orders', name: 'Orders List' },
  { path: '/orders/:id', name: 'Order Detail' },
  { path: '/orders/:id/tracking', name: 'Order Tracking' }
];

2. 布局组件设计

jsx
// 可复用的布局组件
function createLayout(config) {
  const {
    showHeader = true,
    showSidebar = true,
    showFooter = true,
    headerComponent = DefaultHeader,
    sidebarComponent = DefaultSidebar,
    footerComponent = DefaultFooter,
    className = ''
  } = config;

  return function Layout() {
    return (
      <div className={`layout ${className}`}>
        {showHeader && React.createElement(headerComponent)}
        
        <div className="layout-body">
          {showSidebar && (
            <aside className="layout-sidebar">
              {React.createElement(sidebarComponent)}
            </aside>
          )}
          
          <main className="layout-main">
            <Outlet />
          </main>
        </div>
        
        {showFooter && React.createElement(footerComponent)}
      </div>
    );
  };
}

// 创建不同的布局
const MainLayout = createLayout({
  showHeader: true,
  showSidebar: true,
  showFooter: true,
  className: 'main-layout'
});

const AuthLayout = createLayout({
  showHeader: false,
  showSidebar: false,
  showFooter: false,
  className: 'auth-layout'
});

const AdminLayout = createLayout({
  headerComponent: AdminHeader,
  sidebarComponent: AdminSidebar,
  className: 'admin-layout'
});

// 响应式布局
function ResponsiveLayout() {
  const [sidebarOpen, setSidebarOpen] = useState(true);
  const [isMobile, setIsMobile] = useState(false);

  useEffect(() => {
    const checkMobile = () => {
      setIsMobile(window.innerWidth < 768);
      if (window.innerWidth < 768) {
        setSidebarOpen(false);
      }
    };

    checkMobile();
    window.addEventListener('resize', checkMobile);
    
    return () => window.removeEventListener('resize', checkMobile);
  }, []);

  return (
    <div className={`responsive-layout ${sidebarOpen ? 'sidebar-open' : 'sidebar-closed'}`}>
      <header className="layout-header">
        <button 
          className="sidebar-toggle"
          onClick={() => setSidebarOpen(!sidebarOpen)}
        >

        </button>
        <h1>My App</h1>
      </header>

      <div className="layout-body">
        {(sidebarOpen || !isMobile) && (
          <aside className="layout-sidebar">
            <Navigation />
          </aside>
        )}

        <main className="layout-main">
          <Outlet />
        </main>
      </div>
    </div>
  );
}

3. 路由守护和条件渲染

jsx
// 路由守护组件
function ProtectedRoute({ children, requiredPermission, fallback }) {
  const { user, permissions } = useAuth();
  const location = useLocation();

  if (!user) {
    return <Navigate to="/login" state={{ from: location }} replace />;
  }

  if (requiredPermission && !permissions.includes(requiredPermission)) {
    return fallback || <AccessDenied />;
  }

  return children;
}

// 在路由配置中使用守护
function App() {
  return (
    <Routes>
      <Route path="/" element={<Layout />}>
        <Route index element={<Home />} />
        
        {/* 受保护的路由 */}
        <Route 
          path="dashboard" 
          element={
            <ProtectedRoute>
              <Dashboard />
            </ProtectedRoute>
          } 
        />
        
        {/* 需要特定权限的路由 */}
        <Route 
          path="admin/*" 
          element={
            <ProtectedRoute 
              requiredPermission="admin:access"
              fallback={<AccessDenied />}
            >
              <AdminRoutes />
            </ProtectedRoute>
          } 
        />
        
        {/* 角色基础的路由 */}
        <Route 
          path="management/*" 
          element={
            <RoleBasedRoute 
              allowedRoles={['admin', 'manager']}
              fallback={<AccessDenied />}
            >
              <ManagementRoutes />
            </RoleBasedRoute>
          } 
        />
      </Route>
    </Routes>
  );
}

function RoleBasedRoute({ children, allowedRoles, fallback }) {
  const { user } = useAuth();

  if (!user || !allowedRoles.includes(user.role)) {
    return fallback || <Navigate to="/" replace />;
  }

  return children;
}

4. 路由状态管理

jsx
// 路由状态持久化
function useRoutePersistence() {
  const location = useLocation();
  const navigate = useNavigate();

  useEffect(() => {
    // 保存当前路由到sessionStorage
    sessionStorage.setItem('lastRoute', location.pathname + location.search);
  }, [location]);

  const restoreLastRoute = useCallback(() => {
    const lastRoute = sessionStorage.getItem('lastRoute');
    if (lastRoute && lastRoute !== location.pathname) {
      navigate(lastRoute);
    }
  }, [navigate, location]);

  return { restoreLastRoute };
}

// 路由级数据预加载
function useRoutePreloader() {
  const navigate = useNavigate();

  const preloadRoute = useCallback(async (path) => {
    try {
      // 预加载路由对应的代码和数据
      const routeData = await import(`./pages${path}`);
      
      // 预取数据
      if (routeData.preload) {
        await routeData.preload();
      }
      
      console.log(`Route ${path} preloaded successfully`);
    } catch (error) {
      console.error(`Failed to preload route ${path}:`, error);
    }
  }, []);

  const navigateWithPreload = useCallback(async (path, options = {}) => {
    if (options.preload) {
      await preloadRoute(path);
    }
    navigate(path, options);
  }, [navigate, preloadRoute]);

  return { preloadRoute, navigateWithPreload };
}

// 路由分析和追踪
function useRouteAnalytics() {
  const location = useLocation();
  const [routeHistory, setRouteHistory] = useState([]);

  useEffect(() => {
    const routeInfo = {
      path: location.pathname,
      search: location.search,
      timestamp: Date.now(),
      referrer: document.referrer
    };

    // 记录路由访问
    setRouteHistory(prev => [...prev, routeInfo]);

    // 发送分析数据
    analytics.track('page_view', {
      page: location.pathname,
      title: document.title,
      url: window.location.href
    });
  }, [location]);

  const getRouteStats = useCallback(() => {
    const stats = routeHistory.reduce((acc, route) => {
      acc[route.path] = (acc[route.path] || 0) + 1;
      return acc;
    }, {});

    return {
      totalViews: routeHistory.length,
      uniqueRoutes: Object.keys(stats).length,
      mostVisited: Object.entries(stats)
        .sort(([,a], [,b]) => b - a)
        .slice(0, 5)
    };
  }, [routeHistory]);

  return { routeHistory, getRouteStats };
}

总结

React Router v6的路由配置和嵌套路由功能强大:

  1. 灵活的配置方式:JSX声明式和对象配置式
  2. 强大的嵌套支持:支持任意深度的路由嵌套
  3. 布局共享:通过Outlet实现布局组件复用
  4. 相对路径:简化路由间的导航
  5. 条件路由:支持基于权限和条件的路由渲染

合理的路由架构是构建大型React应用的基础。