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

React(TypeScript)中实现独立页面嵌套路由的最佳实践是什么?

React TypeScript 项目详情页路由最佳实践

核心思路

你需要的是项目列表页与详情页完全独立,但共享全局Header/Footer的路由结构——本质是把列表页和详情页放在同一层级路由下,通过路径区分页面,而非用嵌套路由的Outlet将详情页渲染在列表页内部。

具体实现方案(React Router v6+)

1. 全局布局与路由配置

先定义包裹Header、Footer的全局布局,内部用<Outlet/>承载页面内容,再将首页、项目列表、项目详情作为平级路由配置:

// src/routes/index.tsx
import { Routes, Route, Outlet } from 'react-router-dom';
import Header from '../components/Header';
import Footer from '../components/Footer';
import Home from '../pages/Home';
import ProjectsPage from '../pages/ProjectsPage';
import ProjectDetail from '../pages/ProjectDetail';

// 全局布局组件
const GlobalLayout = () => (
  <div className="app-container">
    <Header />
    <main className="page-content">
      <Outlet />
    </main>
    <Footer />
  </div>
);

export default function AppRoutes() {
  return (
    <Routes>
      <Route element={<GlobalLayout />}>
        <Route path="/" element={<Home />} />
        {/* 项目列表页 */}
        <Route path="/projects" element={<ProjectsPage />} />
        {/* 项目详情页,通过动态参数:projectId匹配 */}
        <Route path="/projects/:projectId" element={<ProjectDetail />} />
      </Route>
    </Routes>
  );
}

2. 列表页跳转逻辑

在ProjectsPage中用<Link>组件直接跳转至详情页路径:

// src/pages/ProjectsPage.tsx
import { Link } from 'react-router-dom';
import { Project } from '../types';

interface ProjectsPageProps {
  projects: Project[];
}

export default function ProjectsPage({ projects }: ProjectsPageProps) {
  return (
    <div className="projects-list">
      <h2>已完成项目</h2>
      <div className="project-cards">
        {projects.map(project => (
          <Link 
            key={project.id} 
            to={`/projects/${project.id}`} 
            className="project-card"
          >
            <h3>{project.title}</h3>
            <p>{project.shortDesc}</p>
          </Link>
        ))}
      </div>
    </div>
  );
}

3. 详情页获取路由参数

在ProjectDetail中用useParams读取动态路由参数,加载对应项目数据:

// src/pages/ProjectDetail.tsx
import { useParams } from 'react-router-dom';
import { fetchProjectById } from '../services/projectApi';
import { useEffect, useState } from 'react';
import { Project } from '../types';

export default function ProjectDetail() {
  const { projectId } = useParams<{ projectId: string }>();
  const [project, setProject] = useState<Project | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    const loadProject = async () => {
      try {
        const data = await fetchProjectById(Number(projectId));
        setProject(data);
      } catch (err) {
        setError((err as Error).message);
      } finally {
        setLoading(false);
      }
    };
    loadProject();
  }, [projectId]);

  if (loading) return <div>加载中...</div>;
  if (error) return <div>加载失败:{error}</div>;
  if (!project) return <div>该项目不存在</div>;

  return (
    <div className="project-detail">
      <h1>{project.title}</h1>
      <p>{project.fullDesc}</p>
      <img src={project.coverImg} alt={project.title} />
      {/* 其他详情内容 */}
    </div>
  );
}

为什么这是最佳实践?

  • 路径语义清晰:/projects对应列表,/projects/:projectId对应详情,用户能通过URL直观判断页面位置
  • 页面完全独立:列表与详情互不干扰渲染,避免嵌套路由导致的父组件内容残留问题
  • 维护成本低:路由结构直观,新增项目相关页面(如编辑页)只需在同一层级添加路由即可
  • 契合React Router v6设计理念:全局布局用Outlet统一承载,页面路由平级配置,符合官方推荐的路由组织方式

补充:嵌套路由的适用场景

如果需要在详情页保留列表侧边栏等共享结构,才需要用嵌套路由:

// 调整路由配置
<Route path="/projects" element={<ProjectLayout />}>
  <Route index element={<ProjectsPage />} /> {/* 默认渲染列表 */}
  <Route path=":projectId" element={<ProjectDetail />} /> {/* 详情渲染在ProjectLayout的Outlet中 */}
</Route>

// ProjectLayout组件
const ProjectLayout = () => (
  <div className="project-layout">
    <aside className="project-sidebar">
      <ProjectsSidebar /> {/* 固定侧边导航 */}
    </aside>
    <div className="project-main">
      <Outlet />
    </div>
  </div>
);

但这种场景仅适用于需要共享部分页面结构的情况,若你要的是完全独立的详情页,前面的平级路由方案更合适。

内容的提问来源于stack exchange,提问作者Anil Ferhat Ceran

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 00:31:11