React项目怎么配置路由实现页面跳转
React 里的“页面跳转”通常由两件事组成:一张把 URL 映射到组件的路由表,和触发跳转的动作(点击链接,或者在代码里调用导航函数)。多数配置失败不是不会写,而是版本写法和部署方式没对上。所以先确认版本和路由模式,再动手改,比直接复制一份配置更稳。
适用场景:单页应用需要在多个视图之间切换、带路由参数、或登录成功后跳转。处理动作:先确认 react-router-dom 的大版本和路由模式,再在入口包一层 Router、用 Routes/Route 定义路由表、在页面里用 Link 或 useNavigate 跳转。验证看地址栏是否变化、刷新当前路径是否 404、参数页能否直接打开。边界:BrowserRouter 要求服务端把未知路径回落到 index.html,部署在子目录要配 basename,纯静态托管可退回 HashRouter。
先确认当前场景和目标
动手前先确认四件事:一是项目是否已经装了路由库,装的是哪个大版本;二是路由模式用 BrowserRouter 还是 HashRouter;三是跳转方式是声明式链接为主,还是表单提交后的编程式跳转;四是页面结构是否需要嵌套布局和路由参数。
版本最关键。v5 的写法是 Switch 加 component 或 render,v6 换成了 Routes 加 element,参数也从组件 props 读取改成 useParams。把 v5 示例贴进 v6 项目,最常见的现象是页面空白、控制台提示某个导出不存在。可以先看一下依赖:
# 查看当前安装的路由库版本
npm ls react-router-dom
# 如果还没装(以 v6 写法为例)
npm install react-router-dom
再看部署环境。如果页面由 Nginx、Node 服务或静态托管提供,并且需要用户能直接访问 /users/1 这类地址,就必须让服务端把未命中的路径回落到 index.html,否则刷新会拿到 404。没有条件改服务端配置时,HashRouter 是更省事的退路,代价是地址栏带 #。

按这个顺序处理
建议的顺序是:入口挂 Router → 定义路由表 → 页面内跳转 → 补 404 → 需要时再拆包。下面是一个可替换的通用骨架,v6 写法,路径和组件名按自己的目录改。
第一步,在最外层包一个 Router,整个应用只能有一层:
// src/main.jsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import { BrowserRouter } from 'react-router-dom'
import App from './App'
ReactDOM.createRoot(document.getElementById('root')).render(
)
basename 要和实际部署的子路径一致,部署在根目录就写 "/"。

第二步,用 Routes 和 Route 声明路由表。需要公共头部、侧边栏时,用父路由加 Outlet 占位,子路由写在父路由内部,子路径不要以 / 开头:
// src/App.jsx
import { Routes, Route, Link, Outlet } from 'react-router-dom'
import Home from './pages/Home'
import UserList from './pages/UserList'
import UserDetail from './pages/UserDetail'
import NotFound from './pages/NotFound'
function Layout() {
return (
)
}
export default function App() {
return (
}>
} />
} />
} />
} />
)
}第三步,页面内跳转。普通导航用 Link,它会渲染成可被搜索引擎和键盘操作的 ;只有在提交表单、条件判断之后才需要 useNavigate:

// src/pages/UserList.jsx
import { useNavigate, useSearchParams } from 'react-router-dom'
export default function UserList() {
const navigate = useNavigate()
const [searchParams, setSearchParams] = useSearchParams()
const goDetail = (id) => {
navigate(/users/${id}) // 新增一条历史记录
// navigate(/users/${id}, { replace: true }) // 替换当前记录,返回时不回退到列表
}
return (
goDetail(1)}>查看用户 1
setSearchParams({ page: '2' })}>第二页
)
}详情页用 useParams 取 id,取不到或数据不存在时给出提示,不要直接渲染空对象字段。数据量大或页面较重时,再把 element 换成 React.lazy 加 Suspense 包裹的组件,先保证跳转逻辑跑通,再考虑拆包。
改完后怎么验证
按下面几项逐条走一遍,比只看一次跳转成功更可靠:
点导航链接,地址栏应变化且页面内容切换,浏览器前进、后退按钮能正常来回。
在详情页地址上按 F5 刷新,页面应正常渲染;如果返回 404 或空白,说明服务端未配置路径回落,或 basename 与实际部署路径不一致。
手动在地址栏输入
/users/1、/users/abc和一个不存在的路径,确认参数页能直达、非法参数有提示、未命中走 404 组件。提交表单后调用
navigate,确认成功跳走,并且按浏览器返回键不会回到已提交的页面(需要的话改用replace: true)。看控制台:不应出现“不能在 Router 外使用 useNavigate”之类的报错,也不应出现路由组件未更新的警告。
使用了懒加载时,在网络面板里应看到对应页面的分块文件在首次进入时被请求。
预期信号是:地址栏、页面内容、浏览器历史三者一致,刷新任何一条已定义路由都不会落到白屏。
容易忽略的边界
版本混用:v5 的
Switch、useHistory在 v6 中已不可用,对应Routes、useNavigate;如果项目里同时存在两套写法,先统一版本再改页面,不要边改边升级。嵌套 Router:在组件内部又包了一层 BrowserRouter 会导致跳转异常或路由表失效,整个应用只保留最外层一层。
子路径与相对跳转:部署在
/admin这类子目录时,Router 的basename、静态资源的publicPath、后端回落规则三处要一致,漏一处就会出现刷新后资源 404。权限拦截:登录态判断不要写在渲染期直接改 location,建议用包装组件,未登录时返回
,避免首页闪一下再跳走。navigate(-1)的局限:用户从外部链接直接进入详情页时,历史里没有上一页,回退可能离开站点,这类页面建议提供明确的“返回列表”链接。HashRouter 的适用面:它能绕开服务端回落配置,但地址带
#,部分统计和分享场景需要额外处理。若后续改造成本可控,仍建议优先把服务端回落配好再用 BrowserRouter。不适用条件:服务端渲染、微前端子应用、或已有其他路由框架的项目,不建议直接套用上面这份骨架,需要先确认路由归属和挂载基路径。
