React Router
1、概述
1、React Router 会以三个不同的包发布到npm上,它们分别是:
-
react-router
:路由的核心库,提供了很多的:组件、钩子。 -
react-router-dom
:包含react-router所有内容,并添加一些专门用于DOM的组件,例如<BrowserRouter>
等 -
react-router-native
:包括react-router所有内容,并添加一些专门用于ReactNative的API,例如<NativeRouter>
等
React Router 5
Component
1.<BrowserRouter>
-
作用:
<BrowserRouter>
用于包裹整个应用 -
示例代码:
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { BrowserRouter } from "react-router-dom";
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>
, document.getElementById("root")
);
2.<HashRouter>
-
作用:与
<BrowserRouter>
一样,但是修改的是地址栏的hash值 -
示例代码:
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { BrowserRouter } from "react-router-dom";
ReactDOM.render(
<HashRouter>
<App />
</HashRouter>
, document.getElementById("root")
);
3.<Link>
-
作用:修改URL地址,并且不会发送网络请求
-
注意:它需要在外侧用
<BrowserRouter>
或<HashRouter>
包裹,否则会报错 -
示例代码:
import React from "react";
import { Link } from "react-router-dom";
export default function App() {
return (
<div>
<Link to="/home">Home</Link>
<br />
<br />
<Link to="/about">About</Link>
</div>
);
}
4.NavLink
-
作用:与
<Link>
类似,且可以实现导航高亮的效果(即给了一个"active"
的样式名) -
示例代码:
import React from "react";
import { NavLink } from "react-router-dom";
export default function App() {
return (
<div>
//注意:NavLink默认类名是active
<NavLink to="/home">Home</NavLink>
<br />
<br />
<NavLink to="/about">About</NavLink>
</div>
);
}
5. <Route>
-
作用:根据路径来匹配相对应的组件,随后渲染到页面上
-
示例代码:
import React from "react";
import { Route, Link } from "react-router-dom";
//导入创建的两个组件
import Home from "./components/Home";
import About from "./components/About";
export default function App() {
return (
<div>
<Link to="/home">Home</Link>
<br />
<br />
<Link to="/about">About</Link>
<br />
<br />
<Route path="/home" component={Home} />
<Route path="/about" component={About} />
</div>
);
}
6.<switch>
-
作用:可以提高路由的匹配效率(单一匹配)
-
示例代码:
- 不使用
<switch>
当不使用<switch>
的话,如果后续的地址有多个重复的,那么将会全部匹配并且渲染到页面上
import React from "react";
import { Route, Link } from "react-router-dom";
import Home from "./components/Home";
import About from "./components/About";
import Test from "./components/Test";
export default function App() {
return (
<div>
<Link to="/home">Home</Link>
<br />
<br />
<Link to="/about">About</Link>
<br />
<br />
<Route path="/home" component={Home} />
<Route path="/about" component={About} />
<Route path="/about" component={Test} />
</div>
);
}
- 使用
<switch>
使用<switch>
之后无论后续的地址重复多少个,它都只会匹配第一个相同的地址,然后渲染当前的组件到页面上
import React from "react";
import { Route, Link, Switch } from "react-router-dom";
import Home from "./components/Home";
import About from "./components/About";
import Test from "./components/Test";
export default function App() {
return (
<div>
<Link to="/home">Home</Link>
<br />
<br />
<Link to="/about">About</Link>
<br />
<br />
<Switch>
<Route path="/home" component={Home} />
<Route path="/about" component={About} />
<Route path="/about" component={Test} />
</Switch>
</div>
);
}
7.<Redirect>
-
作用:当所有的路由都没有匹配到时,跳转到Redirect指定的路由
-
示例代码;
import React from "react";
import { Route, Link, Switch, Redirect } from "react-router-dom";
import Home from "./components/Home";
import About from "./components/About";
import Test from "./components/Test";
export default function App() {
return (
<div>
<Link to="/home">Home</Link>
<br />
<br />
<Link to="/about">About</Link>
<br />
<br />
<Switch>
<Route path="/home" component={Home} />
<Route path="/about" component={About} />
//当浏览器中的路径与上述不匹配时,将会被重定向到/home路径上
<Redirect to="/home" />
</Switch>
</div>
);
}
向路由组件传递参数
- params参数传递
{/* params参数传递---路由连接(携带参数) */}
<Link to="/home/tom/18">Home</Link>
{/* params参数传递---注册路由(声明接收) */}
<Route path="/home/:name/:age" component={Home} />
// 接收参数---props.match.params
const { name, age } = props.match.params;
示例代码:
App.jsx代码:
import React from "react";
import { Route, Link, Switch } from "react-router-dom";
import Home from "./components/Home";
export default function App() {
return (
<div>
{/* params参数传递---路由连接(携带参数) */}
<Link to="/home/tom/18">Home</Link>
<Switch>
{/* params参数传递---注册路由(声明接收) */}
<Route path="/home/:name/:age" component={Home} />
</Switch>
</div>
);
}
Home.jsx代码:
import React from "react";
export default function Home(props) {
// 接收参数---props.match.params
const { name, age } = props.match.params;
return (
<>
<div>Home</div>
<div>
接收到的参数为:{name},{age}
</div>
</>
);
}
- search参数传递
{/* search参数传递---路由连接(携带参数) */}
<Link to="/about?name=tom&age=18">About</Link>
{/* params参数传递---注册路由(无需声明接收,正常注册即可) */}
<Route path="/about" component={About} />
// 接收参数--- props.location.search;
const data = props.location.search;
示例代码:
App.jsx代码:
import React from "react";
import { Route, Link, Switch } from "react-router-dom";
import About from "./components/About";
export default function App() {
return (
<div>
{/* search参数传递---路由连接(携带参数) */}
<Link to="/about?name=tom&age=18">About</Link>
<Switch>
{/* params参数传递---注册路由(无需声明接收,正常注册即可) */}
<Route path="/about" component={About} />
</Switch>
</div>
);
}
About.jsx代码:
import React from "react";
export default function About(props) {
// 接收参数--- props.location.search;
const data = props.location.search;
return (
<>
<div>About</div>
{/* 获取到的search是urlencoded编码字符串,需要进行处理 */}
<div>接收到的参数为:{data}</div>
</>
);
}
- state参数传递
{/* state参数传递---路由连接(携带参数) */}
<Link to={{ pathname: "/test", state: { name: "tom", age: 18 } }}>Test</Link>
{/* state参数传递---注册路由(无需声明接收,正常注册即可) */}
<Route path="/test" component={Test} />
// 接收参数--- props.location.state;
const { name, age } = props.location.state;
示例代码:
App.js代码:
import React from "react";
import { Route, Link, Switch } from "react-router-dom";
import Test from "./components/Test";
export default function App() {
return (
<div>
{/* state参数传递---路由连接(携带参数) */}
<Link to={{ pathname: "/test", state: { name: "tom", age: 18 } }}>Test</Link>
<Switch>
{/* state参数传递---注册路由(无需声明接收,正常注册即可) */}
<Route path="/test" component={Test} />
</Switch>
</div>
);
}
Test.js代码
import React from "react";
export default function Test(props) {
// 接收参数--- props.location.state;
const { name, age } = props.location.state;
return (
<>
<div>Test</div>
<div>
接收到的参数为:{name},{age}
</div>
</>
);
}
- 整体代码
App.js代码
import React from "react";
import { Route, Link, Switch } from "react-router-dom";
import Home from "./components/Home";
import About from "./components/About";
import Test from "./components/Test";
export default function App() {
return (
<div>
{/* params参数传递---路由连接(携带参数) */}
<Link to="/home/tom/18">Home</Link>
<br />
<br />
{/* search参数传递---路由连接(携带参数) */}
<Link to="/about?name=tom&age=18">About</Link>
<br />
<br />
{/* state参数传递---路由连接(携带参数) */}
<Link to={{ pathname: "/test", state: { name: "tom", age: 18 } }}>Test</Link>
<br />
<br />
<Switch>
{/* params参数传递---注册路由(声明接收) */}
<Route path="/home/:name/:age" component={Home} />
{/* params参数传递---注册路由(无需声明接收,正常注册即可) */}
<Route path="/about" component={About} />
{/* state参数传递---注册路由(无需声明接收,正常注册即可) */}
<Route path="/test" component={Test} />
</Switch>
</div>
);
}
Home.js代码
import React from "react";
export default function Home(props) {
// 接收参数---props.match.params
const { name, age } = props.match.params;
return (
<>
<div>Home</div>
<div>
接收到的参数为:{name},{age}
</div>
</>
);
}
About.js代码
import React from "react";
export default function About(props) {
// 接收参数--- props.location.search;
const data = props.location.search;
return (
<>
<div>About</div>
{/* 获取到的search是urlencoded编码字符串,需要进行处理 */}
<div>接收到的参数为:{data}</div>
</>
);
}
Test.js代码
import React from "react";
export default function Test(props) {
// 接收参数--- props.location.state;
const { name, age } = props.location.state;
return (
<>
<div>Test</div>
<div>
接收到的参数为:{name},{age}
</div>
</>
);
}
React Router 6
React Router 6与React Router 5.x 版本相比,改变了什么?
-
内置组件的变化移除
<Switch/>
,新增<Routes/>
等 -
语法的变化:
component={About}
变为element={<About/>}
-
新增多个hook:
useParams
、useNavigate
、useMatch
component
1. <Routes/>
1、作用:
-
v6版本移除了
<Switch>
,引入新的替代者<Routes>
-
<Routes>
和<Route>
要配合使用,且必须要用<Routes>
包裹着<Route>
-
<Routes>
相当于一个if语句,如果其路径与当前URL匹配,则会呈现出相对应的组件 -
<Route caseSensitive>
属性用于指定:匹配时是否区分大小写(默认为 false) -
当URL发生变化时,
<Routes>
都会查看其所有子<Route>
元素以找到最佳匹配并呈现组件 -
<Route>
也可以嵌套使用,且可配合useRoutes()
配置 “路由表” ,但需要通过<Outlet>
组件来渲染其子路由。
2、示例代码:
<Routes>
{/* path属性用于定义路径,element属性用于定义当前路径所对应的组件 */}
<Route path="/home" element={<Home />} />
</Routes>
2.<Navigate>
1、作用:只要<Navigate>
组件被渲染,就会修改当前的路径,跳转到指定的路径
2、replace
属性用来控制跳转模式(push或replace,默认是push)
3、示例代码:
import React from "react";
import { Route, Link, Routes, Navigate } from "react-router-dom";
import Home from "./components/Home";
export default function App() {
return (
<div>
<Link to="/home">Home</Link>
<Routes>
<Route path="/home" element={<Home />} />
{/* 当路径为"/"时,就会渲染Navigate组件,随后跳转到"/home"路径去 */}
<Route path="/" element={<Navigate to="/home" />} />
</Routes>
</div>
);
}
3.<NavLink>
1、作用:与v5的作用一样,但可以通过传递一个函数来自定义样式
2、示例代码:
import React from "react";
import { Route, Link, Routes, Navigate, NavLink } from "react-router-dom";
import Home from "./components/Home";
import About from "./components/About";
export default function App() {
return (
<div>
<NavLink
to="/home"
className={({ isActive }) => {
console.log("home", isActive);
return isActive ? "base" : "";
}}
>
Home
</NavLink>
<br />
<br />
<Link to="/about">About</Link>
<Routes>
<Route path="/home" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</div>
);
}
/*
默认情况下,当About的子组件匹配成功,About的导航也会高亮,
当NavLink上添加了end属性后,若About的子组件匹配成功,则About的导航没有高亮效果。
*/
<NavLink to="/about" end>About</NavLink>
4. <Outlet>
-
当产生了嵌套的时候,渲染器对应的后续子路由
-
<Route>
也可以嵌套使用,且可配合useRoutes()
配置 “路由表” ,但需要通过<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" />
}
]
Home.js代码:
import React from "react";
import { NavLink, Outlet } from "react-router-dom";
export default function Home() {
return (
<div>
<h2>Home组件内容</h2>
<div>
<ul>
<li>
{/* 子路由中的to的三种写法:
1. to='/home/news'
2. to='./news'
3. to='news'
*/}
<NavLink to="news">News</NavLink>
</li>
<li>
<NavLink to="message">Message</NavLink>
</li>
</ul>
{/* 指定路由组件呈现的位置
会将路由表中home下的子路由渲染到此处
*/}
<Outlet />
</div>
</div>
);
}
Hooks
1.useRoutes()
1、作用:根据路由表,来动态创建<Routes>
和<Route>
2、示例代码:
路由表配置代码(src/routes/index.js):
import Home from "../components/Home";
import About from "../components/About";
import { Navigate } from 'react-router-dom'
export default [
{
path: '/home',
element: <Home />
},
{
path: '/about',
element: <About />
},
{
path: '/',
element: <Navigate to="/home" />
}
]
App.js代码:
import React from "react";
import {
Link,
useRoutes
} from "react-router-dom";
import routes from "./routes";
export default function App() {
//根据路由表生成对应的路由规则
const element = useRoutes(routes);
return (
<div>
<Link to="/home">Home</Link>
<br />
<br />
<Link to="/about">About</Link>
//生成路由
{element}
</div>
);
}
2. useNavigate()
-
作用:返回一个函数用来实现编程式导航
-
示例代码:
Message.jsx代码:
import React, { useState } from "react";
import { useNavigate } from "react-router-dom";
export default function Message() {
const navigate = useNavigate();
const showDetail = (m) => {
//第一种使用方法:指定具体的路径
// 第一个参数是to(要去的路径),第二个参数是传递的参数
navigate("detail", {
replace: false,
state: {
id: m.id,
title: m.title,
content: m.content,
},
});
};
//第二种使用方法:传入数值进行前进或后退,类似于5.x中的history.go()方法
const go = () => {
navigate(1);
};
const forward = () => {
navigate(-1);
};
return (
<div>
<button onClick={() => showDetail(m)}>查看详情</button>
<button onClick={forward}>前进</button>
<button onClick={go}>后退</button>
</div>
);
}
3.useParams()
-
作用:获取当前匹配的路由所传递的params参数,类似于5.x中的match.params
-
示例代码:
Message.jsx代码:
//与5.x写法相同,在路径上携带参数
<Link to={`detail/${m.id}/${m.title}/${m.content}`}>
{m.title}
</Link>
路由表代码:
{
path: 'detail/:id/:title/:content',
element: <Detail />
}
Detail.jsx代码:
import React from "react";
import { useParams } from "react-router-dom";
export default function Detail() {
//使用useParams()来获取传递过来的参数
const { id, title, content } = useParams();
return (
<ul>
<li>{id}</li>
<li>{title}</li>
<li>{content}</li>
</ul>
);
}
useParams传递的参数:
4. useMatch()
-
作用:返回当前匹配信息,对标5.x中的路由组件的match属性
-
示例代码:
import { useMatch } from "react-router-dom";
const match = useMatch("/home/message/detail/:id/:title/:content");
console.log(match);
5. useSearchParams()
-
作用:用于读取和修改当前位置的URL上的查询字符串
-
返回一个包含两个值的数组,内容分别是:当前的search参数,更新search的函数
3.示例代码:
Message.jsx代码:
<Link
to={`detail?id=${m.id}&title=${m.title}&content=${m.content}`}
>
{m.title}
</Link>
路由表代码无需更改!
Detail.jsx代码:
import React from "react";
import { useSearchParams } from "react-router-dom";
export default function Detail() {
// search:接收到的参数,setSearch可以更新接收到的参数
const [search, setSearch] = useSearchParams();
// 通过调用search上的get方法,来指定获取数据
const id = search.get("id");
const title = search.get("title");
const content = search.get("content");
return (
<ul>
<li>{id}</li>
<li>{title}</li>
<li>{content}</li>
</ul>
);
}
search的值:
6. useLocation()
-
作用:获取当前location信息,对标5.想中的路由组件的
location
属性 -
示例代码:
Message.jsx代码:
<Link
to="detail"
state={{
id: m.id,
title: m.title,
content: m.content,
}}
>
{m.title}
</Link>
路由表代码无需更改!
Detail.jsx代码:
import React from "react";
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>
);
}
7. useInRouterContext()
-
作用:如果组件在的上下文中呈现,则useInRouterContext钩子返回true,否则返回false
-
示例代码:
import { useInRouterContext } from "react-router-dom";
console.log(useInRouterContext());
8. useNavigationType()
-
作用:返回当前的导航类型(用户是如何来到当前页面的)
-
返回值:POP、PUSH、REPLACE
-
备注:POP是指在浏览器中直接打开了这个路由组件(刷新页面)
-
示例代码:
import { useNavigationType } from "react-router-dom";
console.log(useNavigationType());
9. useOutlet()
-
作用:用来呈现当前组件中渲染的嵌套组件
-
示例代码:
import { useOutlet } from "react-router-dom";
console.log(useOutlet());
// 如果嵌套路由没有挂载,则result为null
// 如果嵌套路由已经挂载,则展示嵌套的路由对象
10. useResolvedPath()
-
作用:给定一个URL值,解析其中的:path值、search值、hash值
-
示例代码:
import { useResolvedPath } from "react-router-dom";
console.log(useResolvedPath("/user?id=001&name=tom#qwe"));