# 概述
-
React Router 以三个不同的包发布到 npm 上,它们分别为:
- react-router:路由的核心库,提供了很多的:组件,钩子
- react-router-dom:包含 react-router 所有内容,并添加一些专门用于 DOM 的组件,例如
<BrowserRouter>等 - react-router-native:包含 react-router 所有内容,并添加
一些专门用于 ReactNative 的 API,例如<NativeRouter>等
-
与 React Router 5.x 版本相比,改变了什么?
- 内置组件的变化:移除
<Switch/>,新增<Routes/>等 - 语法的变化:
component={About}变为element={<About/>}等 - 新增多个 Hook:
useParams,useNavigate,useMatch等 官方明确推荐函数式组件了- …
- 内置组件的变化:移除
-
npm i react-router-dom
# Component
# 一级案例
-
App.jsx
import React from "react"; import {NavLink,Routes,Route} from "react-router-dom" import About from "./pages/About" import Home from "./pages/Home" export default function App() { return ( <div> <h1>React Router Demo</h1> //路由链接 <NavLink to='/about'>About</NavLink> <NavLink to='/home'>Home</NavLink> //注册组件 //React Route6 中 switch 改为了 Routes <Routes> <Route path='/about' element={<About/>} /> <Route path='/home' element={<Home/>} /> </Routes> </div>; ) } -
index.jsx
import React from "react"; import ReactDom from "react-dom"; import { BrowserRouter } from "react-router-dom"; import App from "./App"; ReactDom.render( <BrowserRouter> <App /> </BrowserRouter>, document.getElementById("root") ); -
pages 文件夹 —>About.jsx
import React from "react"; export default function About() { return <h1>我是About的内容</h1>; } -
pages 文件夹 —>Home.jsx
import React from "react"; export default function Home() { return <h1>我是Home的内容</h1>; }
# 1. <BrowserRouter>
-
说明:
<BrowserRouter>用于包裹整个应用 -
实例代码:
import React from "react"; import ReactDom from "react-dom"; import { BrowserRouter } from "react-router-dom"; ReactDom.render( <BrowserRouter> //整体结构,通常为App组件 </BrowserRouter>, document.getElementById("root")
# 2. <HashRouter>
- 说明:作用与
<BrowserRouter>一样,但<HashRouter>修改的是地址栏的 hash 值 - 备注:6.x 版本中
<HashRouter>和<BrowserRouter>的用法与 5.x 相同
# 3. <Routes> 与 <Route>
-
v6 版本中移出了先前的
<Switch>,引入了新的替代者:<Routes> -
<Routes>和<Route>要配合使用,且必须要用<Routes>包裹<Route> -
<Route>相当于一个 if 语句,如果其路径与当前 URL 匹配,则呈现其对应的组件 -
<Route cassSensitive>属性用于指定:匹配时是否区分大小写 (默认为 false) -
当 URL 发生变化时,
<Routes>都会查看其所有子<Route>元素以找到最佳匹配并呈现组件 -
<Route>也可以嵌套使用,且可配合useRoutes()配置’路由表’,但需要通过路由表<Outlet>组件来渲染其子路由 -
示例代码:
<Routes> //path属性用与定义路径,element属性用于定义当前路径所对应的组件 <Route path="/login" element={<Login />}></Route> //用于定义嵌套路由,home是一级路由,对应的路径是/home <Route path="home" element={<Home />}> //test1和test2是二级路由,对应的路径是/home/test1 或 /home/test2 <Route path="test1" element={<Test />}></Route> <Route path="test1" element={<Test2 />}></Route> </Route> //Route也可以不写element属性,这时就是用于展示嵌套的路由,所对应的路径是/users/xxx <Route path="users"> <Route path="xxx" element={<Demo />}></Route> </Route> </Routes>
# 4. <Link>
-
作用:修改 URL,且不发送网络请求 (路由链接)
-
注意:外侧需要用
<BrowserRouter>或<HashRouter>包裹 -
实例代码:
import { Link } from "react-router-dom"; function Test() { return ( <div> <Link to="路径">按钮</Link> </div> ); }
# 5. <NavLink>
-
NavLink 自定义高亮类名案例
注意:NavLink 默认类名是 active,下面是指定自定义的 class<NavLink className={({ isActive }) => (isActive ? "base 自定义active类名" : "base ")} />; //或者 function xxName({ isActive }) { return isActive ? "base 自定义active类名" : "base "; }
# 6. <Navigate>
-
作用:只要
<Navigate>组件被渲染,就会修改路径,切换视图 -
replace属性用于控制跳转模式 (push 或 replace,默认是 push) -
示例代码: pages 文件夹 —>Home.jsx
import React, { useState } from "react"; import { Navigate } from "react-router-dom"; export default function Home() { const [sum, setSum] = useState(1); return ( <div> <h1>我是Home的内容</h1> //根据sum的值决定是否切换视图 {sum === 2 ? ( <Navigate to="about" replace={true} /> ) : ( <h2>当前sum的值是:{sum}</h2> )} //Navigate 只要渲染,就会引起视图的切换 //replace不会留下痕迹 <button onClick={() => { setSum(2); }} > 点我将sum变为2 </button> </div> ); } -
示例代码: App.jsx
import React from "react"; import {NavLink,Routes,Route,Navigate} from "react-router-dom" import About from "./pages/About" import Home from "./pages/Home" export default function App() { return ( <div> <h1>React Router Demo</h1> //路由链接 <NavLink to='/about'>About</NavLink> <NavLink to='/home'>Home</NavLink> //注册组件 //React Route6 中 switch 改为了 Routes <Routes> <Route path='/about' element={<About/>} /> <Route path='/home' element={<Home/>} /> // 一渲染视图就切换 <Route path='' element={<Navigate to='/about'/>}> </Routes> </div>; ) }
# 7. <Outlet>
-
src 文件夹 ->routes 文件夹 ->index.js
import About from "./pages/About"; import Home from "./pages/Home"; import Message from "./pages/Message"; import News from "./pages/News"; import { Navigate } from "react-router-dom"; export default { { path:"/about", element:<About/> }, { path:"/home", element:<Home/>, children:[ { //这里不用写/ path:"news", element:<News/>, }, { path:"message", element:<Message/>, } ] }, { path:"/", element:<Navigate to="/about"/> }, } -
App.jsx
import React from "react"; import {NavLink,useRoutes} from "react-router-dom" import routes from "./routes" export default function App() { //根据路由表生成对应的路由规则 const element = useRoutes(routes) return ( <div> <h1>React Router Demo</h1> //路由链接 <NavLink to='/about'>About</NavLink> //end就是:如果我的子级路由匹配了,那我自己本身会失去高亮 //默认情况下,当Home的子组件匹配成功,Home的导航也会高亮 //当NavLink上添加了end属性后,若Home的子组件匹配成功,则Home的导航没有高亮效果 <NavLink end to='/home'>Home</NavLink> //注册组件 {element} </div>; ) } -
pages 文件夹 —>About.jsx
import React from "react"; export default function About() { return ( <div> <h1>我是About的内容</h1> </div> ); } -
pages 文件夹 —>Home.jsx
import React from "react"; import { NavLink, Outlet } from "react-router-dom"; export default function Home() { return ( <div> <h1>我是Home的内容</h1> //这里直接写news,不带/表示:之前那一堆都带着的路径/news,比如说它的父级是home那这里的路径就是/home/news <NavLink to="news">news</NavLink> <NavLink to="message">message</NavLink> // 指定路由组件呈现的位置 <Outlet /> </div> ); } -
pages 文件夹 —>News.jsx
import React from "react"; export default function News() { return <h1>我是News的内容</h1>; } -
pages 文件夹 —>Message.jsx
import React from "react"; export default function Message() { return <h1>我是Message的内容</h1>; }
# Hooks
# 1.useRoutes()
-
src 文件夹 ->routes 文件夹 ->index.js
import About from "./pages/About"; import Home from "./pages/Home"; import { Navigate } from "react-router-dom"; export default { { path:"/about", element:<About/> }, { path:"/home", element:<Home/> }, { path:"/", element:<Navigate to="/about"/> }, } -
App.jsx
import React from "react"; import {NavLink,useRoutes} from "react-router-dom" import routes from "./routes" export default function App() { //根据路由表生成对应的路由规则 const element = useRoutes(routes) return ( <div> <h1>React Router Demo</h1> //路由链接 <NavLink to='/about'>About</NavLink> <NavLink to='/home'>Home</NavLink> //注册组件 {element} </div>; ) }
# 2. 路由的 params 参数:useParams ()
-
src 文件夹 ->routes 文件夹 ->index.js
import About from "./pages/About"; import Home from "./pages/Home"; import Message from "./pages/Message"; import News from "./pages/News"; import Detail from "./pages/News"; import { Navigate } from "react-router-dom"; export default { { path:"/about", element:<About/> }, { path:"/home", element:<Home/>, children:[ { //这里不用写/ path:"news", element:<News/>, }, { path:"message", element:<Message/>, children:[ { path:"detail/:id/:title/:content", element:<Detail/>, }, ] } ] }, } -
pages 文件夹 —>Message.jsx
import React, { useState } from "react"; import { Link, Outlet } from "react-router-dom"; export default function Message() { const [message] = useState([ { id: "001", title: "标题1", content: "锄禾日当午1" }, { id: "002", title: "标题2", content: "锄禾日当午2" }, { id: "003", title: "标题3", content: "锄禾日当午3" }, { id: "004", title: "标题4", content: "锄禾日当午4" }, ]); return ( <div> <h1>我是Message的内容</h1> <ul> {message.map((ele) => { return ( //路由链接 <li key={ele.id}> <Link to={`detail/${ele.id}/${ele.title}/${ele.content}`}> {ele.title} </Link> </li> ); })} </ul> //指定路由组件的展示位置 <Outlet /> </div> ); } -
pages 文件夹 —>Detail.jsx
import React, { useState } from "react"; import { useParams } from "react-router-dom"; export default function Message() { //这样可以获取到params参数 const { id, title, content } = useParams(); return ( <div> <h1>我是Message的内容</h1> <ul> <li>{id}</li> <li>{title}</li> <li>{content}</li> </ul> </div> ); }
# 3. 路由的 search 参数:useSearchParams ()
-
src 文件夹 ->routes 文件夹 ->index.js
import About from "./pages/About"; import Home from "./pages/Home"; import Message from "./pages/Message"; import News from "./pages/News"; import Detail from "./pages/News"; import { Navigate } from "react-router-dom"; export default { { path:"/about", element:<About/> }, { path:"/home", element:<Home/>, children:[ { //这里不用写/ path:"news", element:<News/>, }, { path:"message", element:<Message/>, children:[ { // search参数这里不用加 path:"detail", element:<Detail/>, }, ] } ] }, } -
pages 文件夹 —>Message.jsx
import React, { useState } from "react"; import { Link, Outlet } from "react-router-dom"; export default function Message() { const [message] = useState([ { id: "001", title: "标题1", content: "锄禾日当午1" }, { id: "002", title: "标题2", content: "锄禾日当午2" }, { id: "003", title: "标题3", content: "锄禾日当午3" }, { id: "004", title: "标题4", content: "锄禾日当午4" }, ]); return ( <div> <h1>我是Message的内容</h1> <ul> {message.map((ele) => { return ( //路由链接 <li key={ele.id}> <Link to={`detail?id=${ele.id}&title=${ele.title}&content=${ele.content}`} > {ele.title} </Link> </li> ); })} </ul> //指定路由组件的展示位置 <Outlet /> </div> ); } -
pages 文件夹 —>Detail.jsx
import React, { useState } from "react"; import { useSearchParams } from "react-router-dom"; export default function Message() { //这样可以获取到search参数 const [search, setSearch] = useSearchParams(); const id = search.get("id"); const title = search.get("title"); const content = search.get("content"); return ( <div> <button @click= {()=>setSearch('id=008&title=hhh&content=嘻嘻嘻')}>点我更新search参数</button> <ul> <li>{id}</li> <li>{title}</li> <li>{content}</li> </ul> </div> ); }
# 4. 路由的 state 参数:useLocation ()
-
src 文件夹 ->routes 文件夹 ->index.js
import About from "./pages/About"; import Home from "./pages/Home"; import Message from "./pages/Message"; import News from "./pages/News"; import Detail from "./pages/News"; import { Navigate } from "react-router-dom"; export default { { path:"/about", element:<About/> }, { path:"/home", element:<Home/>, children:[ { //这里不用写/ path:"news", element:<News/>, }, { path:"message", element:<Message/>, children:[ { // state参数这里不用加 path:"detail", element:<Detail/>, }, ] } ] }, } -
pages 文件夹 —>Message.jsx
import React, { useState } from "react"; import { Link, Outlet } from "react-router-dom"; export default function Message() { const [message] = useState([ { id: "001", title: "标题1", content: "锄禾日当午1" }, { id: "002", title: "标题2", content: "锄禾日当午2" }, { id: "003", title: "标题3", content: "锄禾日当午3" }, { id: "004", title: "标题4", content: "锄禾日当午4" }, ]); return ( <div> <h1>我是Message的内容</h1> <ul> {message.map((ele) => { return ( //路由链接 <li key={ele.id}> <Link to="detail" state={{ id: ele.id, title: ele.title, content: ele.content, }} > {ele.title} </Link> </li> ); })} </ul> //指定路由组件的展示位置 <Outlet /> </div> ); } -
pages 文件夹 —>Detail.jsx
import React, { useState } from "react"; import { useLocation } from "react-router-dom"; export default function Message() { const { state: { id, title, content }, } = useLocation(); return ( <div> <ul> <li>{id}</li> <li>{title}</li> <li>{content}</li> </ul> </div> ); }
# 5. 编程式路由导航:useNavigate ()
-
pages 文件夹 —>Message.jsx
import React, { useState } from "react"; import { Link, Outlet, useNavigate } from "react-router-dom"; export default function Message() { const [message] = useState([ { id: "001", title: "标题1", content: "锄禾日当午1" }, { id: "002", title: "标题2", content: "锄禾日当午2" }, { id: "003", title: "标题3", content: "锄禾日当午3" }, { id: "004", title: "标题4", content: "锄禾日当午4" }, ]); const navigate = useNavigate(); function showDetail(ele) { navigate("detail", { replace: false, state: { id: ele.id, title: ele.title, content: ele.content, }, }); } return ( <div> <h1>我是Message的内容</h1> <ul> {message.map((ele) => { return ( //路由链接 <li key={ele.id}> <Link to="detail" state={{ id: ele.id, title: ele.title, content: ele.content, }} > {ele.title} </Link> <button onClick={() => showDetail(ele)}>查看详情</button> </li> ); })} </ul> //指定路由组件的展示位置 <Outlet /> </div> ); } -
components 文件夹 ->Header.jsx
import React from "react"; import {useNavigate} from "react-router-dom" export default function Header() { const navigate = useNavigate() function back(){ navigate(-1 ) } function forward(){ navigate(1) } return ( <div> <h1>React Router Demo</h1> <button onClick={()=>back}><- 后退</button> <button onClick={()=>forward}>前进 -></button> </div>; ) } -
App.jsx
import React from "react"; import {NavLink,useRoutes} from "react-router-dom" import routes from "./routes" import Header from "./components/header" export default function App() { //根据路由表生成对应的路由规则 const element = useRoutes(routes) return ( <div> <Header/> //路由链接 <NavLink to='/about'>About</NavLink> <NavLink to='/home'>Home</NavLink> //注册组件 {element} </div>; ) }
# 6.useMatch()
-
作用:返回当前匹配信息,对应 5.x 中的路由组件的
match属性 -
代码示例
<NavLink to="/login/1/10">登录</NavLink>; const match = useMatch("/login/:x/:y"); console.log(match); //输出内容如下: { params: {x: "1",y:"10"}, pathname:'/login/1/10', pathnameBase:'/login/1/10', pattern:{ path:"/login/:x/:y", caseSensitive:false, end:false } }
# 7.useInRouterContext()
作用:如果组件在 <Router> 的上下文中呈现,则 useInRouterContext 钩子返回 true,否则返回 false。
其实就是只要被 <BrowserRouter> 包裹的返回的都是 true
# 8.useNavigationType()
- 作用:返回当前的导航类型 (用户是如何来到当前页面的)
- 返回值:
POP,PUSH,REPLACE,代表的是你通过哪种方式来到这个路由组件的 - 备注:
POP是指在浏览器中直接打开了这个路由组件 (刷新页面)
# 9.useOutlet()
-
作用:用来呈现当前组件中渲染的嵌套路由
-
示例代码:
const result = useOutlet(); console.log(result); //如果嵌套路由没有挂载,则result为null //如果嵌套路由已经挂载,则展示嵌套的路由对象,可以通过这个对象拿到很多东西,比如:props,ref等
# 10.useResolvedPath()
-
作用:给定一个 URL 值,解析其中的:path,search,hash 值
-
代码实例:
import { useResolvedPath } from "react-router-dom"; console.log(useResolvedPath("/users?id=001&name=tom#qwe)); // 返回:{pathname:'/user',search:'?id=001&name=tom',hash:"#qwe"}