01 一级路由
安装包
在使用路由时,要下载react-router-dom
npm i -D react-router-dom
引入路由
使用路由时需要将路由包裹代码效果如下
其中,BrowserRouter
更好,HashRouter
有兼容性问题
// `BrowserRouter` 更好,`HashRouter` 有兼容性问题
import { BrowserRouter, HashRouter } from "react-router-dom";
const root = ReactDOM.createRoot(
document.getElementById("root") as HTMLElement
);
root.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
);
路由的使用
在点击路由链接时需要跳转到相应页面,在这使用的是route6版本
在react-router-dom
中分别引入如下所示
import { NavLink, Routes, Route } from "react-router-dom";
NavLink
如果需要高亮,Link
不需要高亮
Routes
相当于之前的switch
NavLink
使用
使用方式如下所示,在后面章节中会详细提出更多使用方式
<NavLink className="list-group-item" to="/about">
About
</NavLink>
<NavLink className="list-group-item" to="/home">
Home
</NavLink>
注册路由
-
注册路由:
-
如果想写标签就用
element
不想用标签就用Component
-
和之前一样,如果有相同标签则会匹配第一次也就是第一个匹配到的组件
代码效果如下所示:
<Routes>
<Route path="/about" element={<About />} />
<Route path="/home" element={<Home />} />
<Route path="/about" Component={About} />
<Route path="/home" Component={Home} />
</Routes>
展现标签在
element
后面写入,或者在Component
写入
02 路由重定向
如果是在访问根路由的情况下,这时需要路由的重定向操作
在route6版本中引入了新的组件标签Navigate
,可以组件中使用重定向
在实际的开发中当路由较多时会使用路由表统一管理
点击路由链接
点击路由链接写法和在01
中方式一样没有改变
<NavLink className="list-group-item" to="/about">
About
</NavLink>
<NavLink className="list-group-item" to="/home">
Home
</NavLink>
路由重定向
如要引入的包
- NavLink如果需要高亮,Link不需要高亮
- Routes相当于之前的switch
import { NavLink, Routes, Route, Navigate } from "react-router-dom";
代码展示
- 当访问根路径时候,会重定向到当前设置的路由中
- 如果在标签中引入了
Navigate
当路由变化时必然会引起视图的切换 - 在页面中会自动跳转到
about
页面 caseSensitive
会区分大小写
<Routes>
<Route path="/about" caseSensitive element={<About />} />
<Route path="/home" element={<Home />} />
<Route path="/" element={<Navigate to="/about" />} />
</Routes>
符合条件跳转
- 如果 to 不写会报错,没有
pathname
replace={true}
会替换当前页面,效果就是不会后退页面了;默认是push
<>
<h3>我是Home的内容</h3>
{sum === 2 ? (
<Navigate to="/about" replace={true} />
) : (
<h4>当前的sum值为:{sum} </h4>
)}
<button className="btn btn-primary" onClick={() => setSum(sum + 1)}>
改变sum值
</button>
</>
03 带高亮效果
在使用bootstrap
框架时帮我们定义了好了,如果点击就会自动加上active
如何加上自己想要的样式
const computedClassName = ({ isActive }: any) => {
return isActive ? "list-group-item bunny" : "list-group-item";
};
return(
<NavLink className={computedClassName} to="/about">
About
</NavLink>
<NavLink className={computedClassName} to="/home">
Home
</NavLink>
)
不让父级高亮
- 点击链接进行跳转------开始
- 如果不想让父级路由高亮 在标签中写上
end
- 实例
<NavLink className="list-group-item" end to="/about">
<NavLink className="list-group-item" end to="/about">
About
</NavLink>
<NavLink className="list-group-item" to="/home">
Home
</NavLink>
04 路由表的使用
创建路由表
在src
目录下新建routes/index.tsx
内容如下展示
import { Navigate } from "react-router-dom";
import About from "../page/About";
import Home from "../page/Home";
export default [
{ path: "/about", element: <About /> },
{ path: "/home", element: <Home /> },
{ path: "/", element: <Navigate to="about" /> },
];
需要将木块暴露出去
引入路由表
之后在组件中接受
需要引入包
import { NavLink, useRoutes } from "react-router-dom";
import element from "./routes";
// 定义路由表
const elementList = useRoutes(element);
组件中使用
export default function App() {
const elementList = useRoutes(element);
return (
<>
<div className="row">
<div className="col-xs-2 col-xs-offset-2">
<div className="list-group">
{/* 点击链接进行跳转------开始 */}
<NavLink className="list-group-item" to="/about">
About
</NavLink>
<NavLink className="list-group-item" to="/home">
Home
</NavLink>
{/* 点击链接进行跳转------结束 */}
</div>
</div>
<div className="col-xs-6">
<div className="panel">
<div className="panel-body">
{/* 路由表的使用 */}
{elementList}
</div>
</div>
</div>
</div>
</>
);
}
05 嵌套路由
路由表中
routes/index.tsx
中
嵌套路由和vue
比较像,在父级路由中需要写上children
;以数组的形式
import { Navigate } from "react-router-dom";
import About from "../page/About";
import Home from "../page/Home";
import Message from "./../page/Message";
import News from "./../page/News";
export default [
{ path: "/about", element: <About /> },
{
path: "/home",
element: <Home />,
children: [
{ path: "message", element: <Message /> },
{ path: "news", element: <News /> },
],
},
{ path: "/", element: <Navigate to="about" /> },
];
嵌套路由点击
-
跳转到子级路由方式三种:
-
如果需要跳转到子级路由就需要
/home/news
方式 -
或者直接写
./news
-
再或者直接写
news
-
<li>
<NavLink className="list-group-item" to="./news">
News
</NavLink>
</li>
<li>
{/* 如果需要跳转到子级路由就需要 `/home/news` 方式*/}
<NavLink className="list-group-item" to="./message">
Message
</NavLink>
</li>
自己路由展示
需要引入Outlet
import { Outlet } from "react-router-dom";
{/* 指定路由组件呈现位置 */}
<Outlet />
06 路由传参-params参数
路由表中
注意路径书写格式:detail/:id/:title/:content
import { Navigate } from "react-router-dom";
import About from "../page/About";
import Home from "../page/Home";
import Message from "./../page/Message";
import News from "./../page/News";
import Detail from "../page/Detail";
export default [
{ path: "/about", element: <About /> },
{
path: "/home",
element: <Home />,
children: [
{
path: "message",
element: <Message />,
children: [{ path: "detail/:id/:title/:content", element: <Detail /> }],
},
{ path: "news", element: <News /> },
],
},
{ path: "/", element: <Navigate to="about" /> },
];
路由书写格式,要和传入时候一致,并且在接受时也需要一样
传参给子路由
- 当点击这些标签时候会显示当前页面子路由中的内容
- 需要将内容传递给子路由
- 注意写入方式:to={
detail/${item.id}/${item.title}/${item.content}
import React, { useState } from "react";
import { NavLink, Outlet } from "react-router-dom";
export default function Message() {
const [messages] = useState([
{ id: "001", title: "消息1", content: "锄禾日当午" },
{ id: "002", title: "消息2", content: "汗滴禾下土" },
{ id: "003", title: "消息3", content: "谁知盘中餐" },
{ id: "004", title: "消息4", content: "粒粒皆辛苦" },
]);
return (
<div>
<ul>
{messages.map((item) => {
return (
<li key={item.id}>
<NavLink to={`detail/${item.id}/${item.title}/${item.content}`}>
{item.title}
</NavLink>
</li>
);
})}
</ul>
{/* 路由展示位置---子级路由 */}
<Outlet />
</div>
);
}
注意写时:
<NavLink to={`detail/${item.id}/${item.title}/${item.content}`}> {item.title} </NavLink>
接受参数
import React from "react";
import { useMatch, useParams } from "react-router-dom";
export default function Detail() {
// `useParams` 使用的比较多
// `useMatch` 用的不多,但是要知道下
const { id, title, content } = useParams();
const match = useMatch("/home/message/detail/:id/:title/:content");
console.log(match);
return (
<ul>
<li>
消息的编号:{id},消息的标题:{title},消息的内容{content}
</li>
<li>
消息的编号:{id},消息的标题:{title},消息的内容{content}
</li>
<li>
消息的编号:{id},消息的标题:{title},消息的内容{content}
</li>
</ul>
);
}
07 路由的search参数
路由表
import { Navigate } from "react-router-dom";
import About from "../page/About";
import Home from "../page/Home";
import Message from "./../page/Message";
import News from "./../page/News";
import Detail from "../page/Detail";
export default [
{ path: "/about", element: <About /> },
{
path: "/home",
element: <Home />,
children: [
{
path: "message",
element: <Message />,
children: [{ path: "detail", element: <Detail /> }],
},
{ path: "news", element: <News /> },
],
},
{ path: "/", element: <Navigate to="about" /> },
];
传入参数
import React, { useState } from "react";
import { NavLink, Outlet } from "react-router-dom";
export default function Message() {
const [messages] = useState([
{ id: "001", title: "消息1", content: "锄禾日当午" },
{ id: "002", title: "消息2", content: "汗滴禾下土" },
{ id: "003", title: "消息3", content: "谁知盘中餐" },
{ id: "004", title: "消息4", content: "粒粒皆辛苦" },
]);
return (
<div>
<ul>
{messages.map((item) => {
return (
// 当点击这些标签时候会显示当前页面子路由中的内容
// 需要将内容传递给子路由
<li key={item.id}>
<NavLink
to={`detail?id=${item.id}&title=${item.title}&content=${item.content}`}
>
{item.title}
</NavLink>
</li>
);
})}
</ul>
<Outlet />
</div>
);
}
接受参数
setSearch
更新参数search
通过get("传入需要的键")
方法才能获取到想要的字段
import React from "react";
import { useSearchParams } from "react-router-dom";
export default function Detail() {
const [search, setSearch] = useSearchParams();
const id = search.get("id");
const title = search.get("title");
const content = search.get("content");
return (
<ul>
<li>
<button
className="btn btn-success"
onClick={() => setSearch("id=008&title=还好&content=嘻嘻")}
>
点我更新下search参数
</button>
</li>
<li>{id}</li>
<li>{title}</li>
<li>{content}</li>
</ul>
);
}
const [search, setSearch] = useSearchParams(); // search 负责获取数据 // setSearch 负责更新数据 // 两个使用数组结构的
08 路由的state参数
路由表中
import { Navigate } from "react-router-dom";
import About from "../page/About";
import Home from "../page/Home";
import Message from "./../page/Message";
import News from "./../page/News";
import Detail from "../page/Detail";
export default [
{ path: "/about", element: <About /> },
{
path: "/home",
element: <Home />,
children: [
{
path: "message",
element: <Message />,
children: [{ path: "detail", element: <Detail /> }],
},
{ path: "news", element: <News /> },
],
},
{ path: "/", element: <Navigate to="about" /> },
];
传入参数
import React, { useState } from "react";
import { NavLink, Outlet } from "react-router-dom";
export default function Message() {
const [messages] = useState([
{ id: "001", title: "消息1", content: "锄禾日当午" },
{ id: "002", title: "消息2", content: "汗滴禾下土" },
{ id: "003", title: "消息3", content: "谁知盘中餐" },
{ id: "004", title: "消息4", content: "粒粒皆辛苦" },
]);
return (
<div>
<ul>
{messages.map((item) => {
return (
// 当点击这些标签时候会显示当前页面子路由中的内容
// 需要将内容传递给子路由
<li key={item.id}>
<NavLink
to="detail"
state={{
id: item.id,
title: item.title,
content: item.content,
}}
>
{item.title}
</NavLink>
</li>
);
})}
</ul>
<Outlet />
</div>
);
}
接受参数
在接受参数时,和使用useState
方式差不多
import { useLocation } from "react-router-dom";
export default function Detail() {
const {
state: { id, title, content },
} = useLocation();
return (
<ul>
<li>{id}</li>
<li>{title}</li>
<li>{content}</li>
</ul>
);
}
09 编程式路由导航
路由表中
import { Navigate } from "react-router-dom";
import About from "../page/About";
import Home from "../page/Home";
import Message from "./../page/Message";
import News from "./../page/News";
import Detail from "../page/Detail";
export default [
{ path: "/about", element: <About /> },
{
path: "/home",
element: <Home />,
children: [
{
path: "message",
element: <Message />,
children: [{ path: "detail", element: <Detail /> }],
},
{ path: "news", element: <News /> },
],
},
{ path: "/", element: <Navigate to="about" /> },
];
传入参数
- 编程式路由导航
- 可以实现路由跳转的功能
- 如果后面传入的参数为
replacr:true
表示替换当前页面 - navigate(-1) 表示后退
- navigate(1) 表示前进
import React, { useState } from "react";
import { NavLink, Outlet, useNavigate } from "react-router-dom";
export default function Message() {
const [messages] = useState([
{ id: "001", title: "消息1", content: "锄禾日当午" },
{ id: "002", title: "消息2", content: "汗滴禾下土" },
{ id: "003", title: "消息3", content: "谁知盘中餐" },
{ id: "004", title: "消息4", content: "粒粒皆辛苦" },
]);
const navigate = useNavigate();
const showDatail = (item: any) => {
/**
* 编程式路由导航
* 可以实现路由跳转的功能
* 如果后面传入的参数为 `replacr:true` 表示替换当前页面
* navigate(-1) 表示后退
* navigate(1) 表示前进
*/
navigate("detail", {
replace: true,
state: {
id: item.id,
title: item.title,
content: item.content,
},
});
};
return (
<div>
<ul>
{messages.map((item) => {
return (
// 当点击这些标签时候会显示当前页面子路由中的内容
// 需要将内容传递给子路由
<li key={item.id}>
<NavLink
to="detail"
state={{
id: item.id,
title: item.title,
content: item.content,
}}
>
{item.title}
</NavLink>
<button
className="btn btn-danger"
onClick={() => showDatail(item)}
>
查看详情
</button>
</li>
);
})}
</ul>
<Outlet />
</div>
);
}
重点在:
- 要使用
navigate
进行编程式路由导航navigate("detail", { replace: true, state: { id: item.id, title: item.title, content: item.content, }, });
接受参数
import { useLocation } from "react-router-dom";
export default function Detail() {
const {
state: { id, title, content },
} = useLocation();
return (
<ul>
<li>{id}</li>
<li>{title}</li>
<li>{content}</li>
</ul>
);
}
10 路由上下文环境判断
- 在路由中是否处于上下文环境中,可以使用
useOutletContext
需要引入
import { useOutletContext } from "react-router-dom";
判断是否在上下文环境
// 只要被 `BrowserRouter` 包裹就代表是true
console.log(useOutletContext()); // true
11 返回当前导航类型
需要引入包useNavigationType
import { useOutletContext } from "react-router-dom";
// 返回当前导航类型(用户是怎么来到这个页面的)
console.log(useNavigationType());
12 呈现当前组件中嵌套路由
import { useOutletContext } from "react-router-dom";
// 呈现当前组件中嵌套路由
console.log(useOutlet());