嵌套路由及传参
嵌套路由及传参方式和常用 Hook
一、路由表
import { Navigate } from "react-router-dom";
// 一级路由
import Home from "../pages/Home";
import About from "../pages/About";
// Home 下的二级路由
import News from "../pages/News";
import Message from "../pages/Message";
// Message 下的三级路由
import MsgDetail from "../pages/Detail";
const routes = [
{
path: "/about",
element: <About />,
},
{
path: "/home",
element: <Home />,
children: [
{
path: "news",
element: <News />,
},
{
path: "message",
element: <Message />,
children: [
{
path: "detail",
element: <MsgDetail />,
},
],
},
],
},
{
path: "/",
element: <Navigate to="/home" />,
},
];
export default routes;
二、Home 路由组件
-
Home 组件内容
import React, { useState } from "react"; import { Navigate, NavLink, Outlet } from "react-router-dom"; export default function Home() { const [sum, setSum] = useState(0); const addSum = () => { setSum(sum + 1); }; return ( <div> <h3>我是home的内容</h3> {sum === 3 ? <Navigate to="/about" /> : <p>{sum}</p>} <button onClick={addSum}>点击变成2</button> <div> <NavLink to="news">News</NavLink> <NavLink to="message">Message</NavLink> {/* 指定路由组件展示位置 */} <Outlet /> </div> </div> ); } -
二级路由 Message
import React, { useState } from "react"; import { Link, Outlet } from "react-router-dom"; export default function Message() { const [msgs, setMsgs] = useState([ { id: "001", title: "消息1", content: "锄禾日当午," }, { id: "002", title: "消息2", content: "汗滴禾下土." }, { id: "003", title: "消息3", content: "谁知盘中餐," }, { id: "004", title: "消息4", content: "粒粒皆辛苦." }, ]); return ( <div> <ul> {msgs.map((item) => { return ( <li key={item.id}> <Link to="detail">{item.title}</Link> </li> ); })} </ul> {/* 指定路由组件展示位置 */} <Outlet /> </div> ); } -
三级路由 Detail
import React from "react"; export default function Detail() { return ( <div> <ul> <li>111</li> <li>222</li> <li>333</li> </ul> </div> ); }
三、路由传参 params 形式
-
Message
import React, { useState } from "react"; import { Link, Outlet } from "react-router-dom"; export default function Message() { const [msgs, setMsgs] = useState([ { id: "001", title: "消息1", content: "锄禾日当午," }, { id: "002", title: "消息2", content: "汗滴禾下土." }, { id: "003", title: "消息3", content: "谁知盘中餐," }, { id: "004", title: "消息4", content: "粒粒皆辛苦." }, ]); return ( <div> <ul> {msgs.map((item) => { return ( <li key={item.id}> <Link to={`detail/${item.id}/${item.title}/${item.content}`}> {item.title} </Link> </li> ); })} </ul> {/* 指定路由组件展示位置 */} <Outlet /> </div> ); } -
调整路由表
const routes = [ ... { path: "/home", element: <Home />, children: [ { path: "news", element: <News />, }, { path: "message", element: <Message />, children: [ { path: "detail/:id/:title/:content", element: <MsgDetail />, }, ], }, ], }, ... ]; -
Detail 接受参数并渲染
import React from "react"; import { useMatch, useParams } from "react-router-dom"; export default function Detail() { const { id, title, content } = useParams(); const x = useMatch("/home/message/detail/:id/:title/:content"); console.log(x); return ( <div> <ul> <li>{id}</li> <li>{title}</li> <li>{content}</li> </ul> </div> ); }
四、路由传参 search 形式
-
路由表还原
const routes = [ ... { path: "/home", element: <Home />, children: [ { path: "news", element: <News />, }, { path: "message", element: <Message />, children: [ { path: "detail", element: <MsgDetail />, }, ], }, ], }, ... ]; -
Message 调整传参方式
export default function Message() { const [msgs, setMsgs] = useState([ { id: "001", title: "消息1", content: "锄禾日当午," }, { id: "002", title: "消息2", content: "汗滴禾下土." }, { id: "003", title: "消息3", content: "谁知盘中餐," }, { id: "004", title: "消息4", content: "粒粒皆辛苦." }, ]); return ( <div> <ul> {msgs.map((item) => { return ( <li key={item.id}> <Link to={`detail?id=${item.id}&title=${item.title}&content=${item.content}`} > {item.title} </Link> </li> ); })} </ul> {/* 指定路由组件展示位置 */} <Outlet /> </div> ); } -
Detail 接收参数
import React from "react"; import { useLocation, useSearchParams } from "react-router-dom"; export default function Detail() { // 方法1 const [search, setSearch] = useSearchParams(); const obj = { id: search.get("id"), title: search.get("title"), content: search.get("content"), }; // 方法2 const x = useLocation(); console.log(x); console.log(x.search); // ?id=123&title=234&content=345 return ( <div> <ul> <li>{obj.id}</li> <li>{obj.title}</li> <li>{obj.title}</li> </ul> {/* 不能更新单个,只更新一个的话, 会认为其他参数没传 */} <button onClick={() => setSearch("id=123&title=234&content=345")}> 点我更新参数 </button> </div> ); }
五、路由传参 state 形式
-
Message 修改传参方式
export default function Message() { return ( ... <Link to="detail" state={{ id: item.id, title: item.title, content: item.content, }} > {item.title} </Link> ... ); } -
Detail 接收
import { useLocation } from "react-router-dom"; export default function Detail() { const { state } = useLocation(); return ( <div> <ul> <li>{state.id}</li> <li>{state.title}</li> <li>{state.content}</li> </ul> </div> ); }
六、编程式路由导航
-
useNavigate 的使用, Message 修改传参方式即可, Detail 不用改
import { Link, Outlet, useNavigate } from "react-router-dom"; export default function Message() { const navigate = useNavigate(); const showDetail = (item) => { navigate("detail", { // replace: false, state: { id: item.id, title: item.title, content: item.content, }, }); }; return ( ... <li key={item.id}> <Link to="detail" state={{ id: item.id, title: item.title, content: item.content, }} > {item.title} </Link> <button onClick={() => showDetail(item)}>点我查看详情</button> </li> ... ); }
七、其他几个 hook
- 任何组件或者元素是否被 BrowserRouter、HashRouter 包裹
console.log(useInRouterContext()); // true - 返回当前的导航类型 POP(刷新页面)/PUSH/REPLACE
console.log(useNavigationType()); // POP - 呈现当前组建中渲染的嵌套路由, null 为当前页面组件还未挂载
console.log(useOutlet()); - 解析 URL
console.log(useResolvedPath("/d1/d2?id=123&title=hello#qwe")); // {pathname: '/d1/d2', search: '?id=123&title=hello', hash: '#qwe'}