今天的学习之旅就像一场奇幻的冒险!React Router Dom 就是我的魔法地图,让单页面应用(SPA)变成了充满神秘房间的城堡。让我们点亮火把,开始探索这个奇妙世界吧!
🌍 前端路由 vs 后端路由:地图制造者之争
想象一下你在玩《塞尔达传说》:
- 后端路由像每次进新房间都要找NPC重新要地图——每次点击链接,服务器就给你一张全新地图(完整HTML页面)。虽然简单直接,但每次加载都要重新画整张地图,林克跑得气喘吁吁。
// 传统后端路由:每次请求返回完整页面
app.get('/about', (req, res) => res.sendFile('about.html'))
- 前端路由则像获得了希卡之石——首次加载拿到万能地图(JS bundle),之后只需魔法传送(JS动态渲染)。React Router Dom 就是这块神奇的石头!
// 前端路由:只更新局部内容
<Route path="/about" element={<About/>} />
为什么选择前端路由?因为:
- 闪电侠速度:页面切换如德芙般丝滑
- 省流量冠军:只需传输数据而非重复加载框架
- 前后端分离:前端工程师终于不用跪求后端改路由了!🎉
MVC (Model-View-Controller)
-
分层结构:
- Model(模型) :负责管理应用程序的数据逻辑,即业务逻辑和数据访问。
- View(视图) :显示数据给用户,并发送用户的命令到控制器。
- Controller(控制器) :接收输入并转换它为命令发送给模型或视图。
-
工作流程:
- 用户与View交互,触发事件后传递给Controller。
- Controller处理这些事件,可能调用Model进行数据更新。
- Model一旦更新完成,通知View进行相应的UI更新。
-
特点:
- 强调将数据管理和UI分离。
- 控制器作为中间人协调模型和视图之间的通信。
- 更适合传统的服务器端应用开发。
MVVM (Model-View-ViewModel)
-
分层结构:
- Model(模型) :与MVC中的模型类似,代表数据和业务逻辑。
- View(视图) :展示数据并与用户交互,但不直接与Model交互。
- ViewModel(视图模型) :作为视图的抽象,通过数据绑定机制连接Model和View。它包含视图所需要的所有属性和逻辑,并能响应视图的变化以及更新模型。
-
工作流程:
- ViewModel通过观察者模式监听Model的变化,并在自身状态改变时自动更新View。
- View也可以通过数据绑定直接反映ViewModel的状态变化,无需手动更新。
-
特点:
- 数据绑定是核心,减少了大量手动更新UI的代码。
- 视图和模型之间没有直接联系,全部通过ViewModel进行交互。
- 更加适合现代的客户端应用,特别是那些需要动态更新UI的应用,如单页应用(SPA)。
-
后端路由
早期只有后端路由 server -> 启动http -> 路由(后端) -> 响应html网页 传统的后端驱动的web 开发方式 展示下一个页面 再来一个请求 / /about
- 优点是足够简单
- 前后端耦合 后端要写前端的页面
- 浪费沟通时间
- 逻辑,数据库,套页面 MVC 开发方式 Model(数据) View(视图) Controller(控制器)
- 不再以返回页面为主
- /api/user/123 接口 返回 JSON 数据
-
前后端分离
MVVM Model(fetch api) View(JSX) ViewModel(视图模型层 useState,数据绑定JSX)
- 前后端联调 api开发文档, 约定
- 前后端分离开发,以API开发文档为约定
- 前端当家作主
- 前端也有了路由 react-router-dom /user/:id path 页面级别组件
- html/css/js react 框架 useState useEffect fetch 请求后端 api接口, 拿到数据 完成web 应用 PC/Mobile/App/小程序/桌面端 大前端
🧙 安装魔法卷轴:初始化仪式
安装咒语简单得像在霍格沃茨点餐:
pnpm install react-router-dom
然后在主神殿(App.jsx)召唤三大守护神:
import {
BrowserRouter as Router, // 魔法传送门
Routes, // 路线图容器
Route // 单条探险路径
} from 'react-router-dom'
就像哈利需要9¾站台才能进入魔法世界,整个应用必须包裹在<Router>中:
function App() {
return (
<Router> {/* 开启魔法结界 */}
<Routes> {/* 路线图在此展开 */}
<Route path="/" element={<Home/>} />
...
</Routes>
</Router>
)
}
🗺️ 绘制探险地图:路由配置艺术
一级路径:主城街道
<Route path="/" element={<Home />} /> // 中央广场
<Route path="/about" element={<About />} /> // 情报屋
<Route path="/user/:id" element={<UserProfile />} /> // 居民档案室
这里的:id就像万能钥匙孔——匹配任意用户ID。访问/user/123时,会神奇地变成:
const UserProfile = () => {
const { id } = useParams();
useEffect(() => {
console.log(window.location);
}, [])
return (
<>
UserProfile {id}
</>
)
}
这里作一个简单的演示,我们在URL的ID值会通过useParams()获取
嵌套路由:房间中的密室
产品商店里藏着更多房间:
<Route path="/products" element={<Products />}>
<Route path=":productId" element={<ProductDetails />} /> // 商品详情暗室
<Route path="new" element={<NewProduct />} /> // 新品铸造室
</Route>
这相当于:
/products → 商店大门
/products/new → 新品展示台
/products/fortnite → 堡垒之夜专柜
🧩 神秘占位符:Outlet组件
在Products组件中,这个神奇标记,就像一个占位符,当我们进入二级路由URL,二级路由的内容会显示在占位符的位置
import { Outlet } from "react-router-dom"
function Products() {
return (
<>
<h1>产品列表</h1>
<Outlet /> {/* 二级路由在此显形! */}
</>
)
}
<Outlet>就像哆啦A梦的任意门:
- 当访问
/products→ 显示空白门框 - 访问
/products/new→ 门后出现<NewProduct>房间 - 访问
/products/123→ 门后展示<ProductDetails>
可能这么说大家不理解,我们就以掘金为例,我们进入二级路由整个页面时不会变化的,只有占位符的位置会显示不同二级路由的内容:
🕵️ 获取探险线索:路由参数解析
在UserProfile组件中,我们使用侦探工具包:
import { useParams } from 'react-router-dom'
function UserProfile() {
const { id } = useParams() // 提取URL中的ID
return <div>正在查看用户 {id} 的档案</div>
}
useParams()就像福尔摩斯的放大镜:
- 当URL是
/user/elonmusk→ 放大镜显示{ id: 'elonmusk' } - 当URL是
/user/007→ 放大镜显示{ id: '007' }
还可以用useEffect监听路径变化:
useEffect(() => {
console.log(`侦探发现新目标:${id}`)
}, [id]) // id变化时触发
🔗 导航的正确姿势:超链接陷阱
在Home组件中,我发现了危险操作:
// 危险!会导致页面刷新
<a href="http://localhost:5173/about">About</a>
这就像用炸药开门——虽然能到达目的地,但会把整个城堡(SPA体验)炸毁!正确方式是使用React Router的<Link>:
import { Link } from 'react-router-dom'
<Link to="/about">About</Link> // 丝滑的密道传送
这里我们用的时超链接,可以很明显的感受到页面的刷新:
为什么重要?
| 方式 | 效果 | 用户体验 |
|---|---|---|
<a href> | 整页刷新,重置所有状态 | 像被踢出城堡 |
<Link to> | 局部更新,保持应用状态 | 穿墙术 |
🧭 RESTful风格路由:冒险者公约
React Router完美支持RESTful规范,就像奇幻世界的通用语言:
// 符合RESTful的路由设计
<Route path="/posts" element={<PostList />}>
<Route path="new" element={<NewPost />} /> // POST 创建
<Route path=":id" element={<PostDetail />} /> // GET 读取
<Route path=":id/edit" element={<EditPost />} />// PATCH 更新
</Route>
HTTP方法与路由的默契配合:
| 方法 | 路径 | 作用 | 好比... |
|---|---|---|---|
| GET | /posts | 获取文章列表 | 查看任务公告栏 |
| POST | /posts | 创建新文章 | 张贴新悬赏令 |
| GET | /posts/:id | 获取单篇文章 | 阅读特定任务详情 |
| PATCH | /posts/:id | 更新文章 | 修改任务描述 |
| DELETE | /posts/:id | 删除文章 | 撕下过期悬赏令 |
🌟 终极启示录:路由哲学
经过今天的探险,我领悟到:
- 组件即王国
每个Route对应一个自治领地,通过Props传递信息 - URL即坐标
像地理坐标一样精确描述应用状态:
https://app.com/products/tech?sort=price#reviews - 路由即叙事
精心设计的路由如同故事线:
/welcome → /products → /cart → /checkout - 嵌套即套娃
路由层级反映UI层级,像俄罗斯套娃般严丝合缝
当夕阳的余晖洒在代码编辑器上,我合上魔法书感叹:React Router Dom 就像一本会自我重写的魔法地图。它不直接创造内容,而是定义了内容呈现的时空规则——何时何地展示何种组件。