“开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 7 天,点击查看活动详情”
1. 简介
React和Vue一样都是单页面应用(SPA)加载单个HTML 页面并在用户与应用程序交互时动态更新该页面的Web应用程序,单页面应用需要实现多页面应用的效果就需要使用react-router-dom
2. 代码学习
1. 安装
pnpm i react-router-dom @types/react-router-dom
2. 创建三个页面
export function home() {
return <div>
<h1>home首页</h1>
</div>
}
export function Cart() {
return <div>
<h1>汽车首页</h1>
</div>
}
export function CartDetail() {
return <div>
<h1>汽车首页详细</h1>
</div>
}
- 在项目核心文件main.tsx中导入路由相关组件
- 路由的类型
import {HashRouter, BrowserRouter} from "react-router-dom";- BrowserRouter 对应Vue的history模式
- HashRouter 对应Vue的hash模式
- 以上二选一使用
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( <React.StrictMode> <BrowserRouter> <App/> </BrowserRouter> </React.StrictMode> )
3. 页面注册到路由
```tsx
import { Route, Routes } from "react-router-dom";
import { Cart, CartDetail } from "./view/cart";
import Home from "./view/home";
function App() {
return (
<div className="App">
<Routes>
<Route path="/" element={<Home/>}></Route>
<Route path="cart" element={<Cart/>}></Route>
</Routes>
</div>
)
}
```
- Routes 路由容器,在它的内部定义管理所有的Route
- Route 配置页面与路由的关系
- path 就是路由地址
- element 导入的组件
- 注册二级路由 Outlet,类似于Vue中的Router-view
- 页面修改
import { Outlet } from "react-router-dom"; export function Cart() { return <div> <h1>汽车首页</h1> <Outlet></Outlet> </div> }- 路由组件修改
function App() { return ( <div className="App"> <Routes> <Route path="/" element={<Home/>}></Route> <Route path="cart" element={<Cart/>}> <Route path=":id" element={<CartDetail/>}/> </Route> </Routes> </div> ) }- 只是在Route内又加入了一个Route
- 打开我们的路由详情页http://127.0.0.1:5173/cart/123 就可以看到二级目录
- 如果还有三级,在二级Route中套入Route,同理二级文件中也需要加入Outlet
- 页面组件
import { Outlet } from "react-router-dom"; export function Cart() { return <div> <h1>汽车首页</h1> <Outlet></Outlet> </div> } export function CartDetail() { return <div> <h2>汽车首页详细</h2> <div> <Outlet></Outlet> </div> </div> } export function DetailRemark() { return <div> <span>汽车详情描述</span> </div> }- 路由文件
import { Route, Routes } from "react-router-dom"; import { Cart, CartDetail, DetailRemark } from "./view/cart"; import Home from "./view/home"; function App() { return ( <div className="App"> <Routes> <Route path="/" element={<Home/>}></Route> <Route path="cart" element={<Cart/>}> <Route path=":id" element={<CartDetail/>}> <Route path="remark" element={<DetailRemark/>}/> </Route> </Route> </Routes> </div> ) }- 访问三级目录http://127.0.0.1:5173/cart/123/remark
- 访问下级路由时,默认是打开上级目录的
4. 注册404页面
- 创建组件
- 注册404页面路由
function App() { return ( <div className="App"> <Routes> <Route path="/" element={<Home/>}></Route> <Route path="cart" element={<Cart/>}> <Route path=":id" element={<CartDetail/>}> <Route path="remark" element={<DetailRemark/>}/> </Route> </Route> <Route path="*" element={<Page404/>}></Route> </Routes> </div> ) } - path使用了
*星号,同时还需要把该路由放到最下面
5. 路由跳转 Link组件
import { Link, Outlet } from "react-router-dom";
export function Cart() {
return <div>
<h1>汽车首页</h1>
<nav>
<Link to="/cart/1">车辆1</Link>
<Link to="/cart/2">车辆2</Link>
</nav>
<Outlet></Outlet>
</div>
}
- 在页面上看不到多大变化,但是可以通过浏览器的URL看到发生了改变
6. 参数传递
- PathParams传参
- 需要修改路由的path
<Route path=":id" element={<CartDetail/>} />- :id 就是 我们传递的参数,还可以修改为其他名称或者传递多个
<Route path=":name" element={<CartDetail/>} /> <Route path=":id/:name" element={<CartDetail/>} />- 通过Link传递参数
<Link to="/cart/1">车辆1</Link> <Link to="/cart/2">车辆2</Link> <Link to="/cart/1/捷豹">捷豹</Link>- 获取参数 useParams
let params = useParams(); export function CartDetail() { let params = useParams(); return <div> <h2>汽车首页详细{params.id}</h2> <div> <Outlet></Outlet> </div> </div> }- 通过点击不同的link 就会显示不同的页面了
- SearchParams 传参
- 修改我们的Link组件
<Link to="/cart/1?name=捷豹&color=蓝色">车辆1</Link>- 使用 useSearchParams Hook
export function CartDetail() { let params = useParams(); let [searchParams, setSearchParams] = useSearchParams(); return <div> <h2>汽车首页详细{params.id}</h2> <div> searchParams 传参 <p>{searchParams.get("name")}</p> <p>{searchParams.get("color")}</p> </div> <div> <Outlet></Outlet> </div> </div> }- 也可以通过setSearchParams修改参数,和setStatus一样
7. 编程式导航
- 通过Js编程的方式进行路由跳转
- 使用Hook useNavigate
import { useNavigate } from "react-router-dom";
export function Cart() {
let navigate = useNavigate();
return <div>
<h1>汽车首页</h1>
<nav>
<button onClick={()=>navigate('/cart/3')}>车辆3</button>
</nav>
<Outlet></Outlet>
</div>
}
-
传递参数
- search 参数
<button onClick={()=>navigate('/cart/4?name=特斯拉&color=白色')}>车辆4</button>- params 参数
<button onClick={()=>navigate('/cart/3')}>车辆3</button>- state 参数
navigate('/cart/4', { state: {name:'tom',age:"20"} })- state参数获取需要使用 hook ** useLocation **
export function CartDetail() { const state = useLocation() return <div> <h2>汽车首页详细{params.id}</h2> {state.state?.name} {state.state?.color} </div> }
3. 总结
- 通过本章学习了把单页面应用变为多页面应用,并且进行路由嵌套,路由跳转,路由传参
1. 三种不同传参的方法的区别
- params传参
- 优点:刷新页面,参数不丢失
- 缺点:1.只能传字符串,传值过多url会变得很长 2. 参数必须在路由上配置.
- 举例:
:path
- search传参
- 优点:刷新页面,参数不丢失
- 缺点:只能传字符串,传值过多url会变得很长,获取参数需要使用hooks useSearchParams
- 举例:
<Link to="/cart/1?name=捷豹&color=蓝色">车辆1</Link>
- state传参
- 优点:可以传对象
- 缺点:刷新页面,参数丢失, 使用 useLocation 获取参数
- 举例:
<button onClick={() => navigate('/cart/5', { state: {name:'路虎',color:"黑色"} })}>车辆4</button>