React Router 6以三个不同的包发布到 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/>}
等。useParams
、useNavigate
、useMatch
等。函数式组件
说明:
基于React Router的web应用,根组件应该是一个router组件(BrowserRouter、HashRouter),<BrowserRouter>
和HashRouter
就是router根组件,用于包裹整个应用。<HashRouter>
作用与<BrowserRouter>
一样,但<HashRouter>
修改的是地址栏的hash值。
< BrowserRouter
// 所有路由的基础地址
basename = { optionalString }
// 如果设置为true,路由router将会在跳转的时候进行整个页面刷新
forceRefresh = { optionalBool }
// 用来确认是否跳转,默认使用window.confirm
getUserConfirmation = { optionalFunc }
// location.key的长度,默认为6
keyLength = { optionalNumber }
>
</ BrowserRouter >
备注
:6.x版本中<HashRouter>
、<BrowserRouter>
的用法与 5.x 相同。
示例代码
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
ReactDOM.render(
<BrowserRouter>
{/* 整体结构(通常为App组件) */}
<App/>
</BrowserRouter>,root
);
v6版本中移出了先前的<Switch>
,引入了新的替代者
:<Routes>
。
<Routes>
和 <Route>
要配合使用,且必须要用<Routes>
包裹<Route>
,<Routes>
会迭代它下面的所有<Route>
子组件,并只渲染第一个路径匹配的
,这样只要匹配到了第一个就不会再往下匹配了。当URL发生变化时,<Routes>
都会查看其所有子 <Route>
元素以找到最佳匹配并呈现组件 。
<Routes>
和 <Route>
可由useRoutes()
配置 “路由表”生成路由代替
路由匹配
是通过将 <Route>组件的path属性
与当前的location的pathname
进行比较来完成的。 当一个<Route>
匹配了 ,它所对应的组件内容将被渲染出来。
<Route caseSensitive>
属性用于指定匹配时是否区分大小写,增加caseSensitive就区分大小写。
<Route>
也可以嵌套使用,但需要通过 <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="test2" element={<Test2/>}></Route>
</Route>
//Route也可以不写element属性, 这时就是用于展示嵌套的路由 .所对应的路径是/users/xxx
<Route path="users">
<Route path="xxx" element={<Demo />} />
</Route>
</Routes>
Link
作用
: 修改URL,且不发送网络请求(路由链接)。
注意
: 外侧需要用<BrowserRouter>
或<HashRouter>
包裹。
示例代码
import { Link } from "react-router-dom";
function Test() {
return (
<div>
<Link to="/路径">按钮</Link>
</div>
);
}
NavLink
作用
: 与<Link>
组件类似,且可实现导航的“高亮”效果。示例代码
// 注意: NavLink默认类名是active,下面是指定自定义的class
//自定义样式
<NavLink
to="login"
className={({ isActive }) => {
console.log('home', isActive)
return isActive ? 'base one' : 'base'
}}
>login
</NavLink>
/*
默认情况下,当Home的子组件匹配成功,Home的导航也会高亮,
当NavLink上添加了end属性后,若Home的子组件匹配成功,则Home的导航没有高亮效果。
*/
<NavLink to="home" end >home</NavLink>
Navigate
作用
:只要<Navigate>
组件被渲染,就会修改路径,切换视图。示例代码
import React,{useState} from 'react'
import {Navigate} from 'react-router-dom'
export default function Home() {
const [sum,setSum] = useState(1)
return (
<div>
<h3>我是Home的内容</h3>
{/* 根据sum的值决定是否切换视图 */}
{sum === 1 ? <h4>sum的值为{sum}</h4> : <Navigate to="/about" replace />}
<button onClick={()=>setSum(2)}>点我将sum变为2</button>
</div>
)
}
作用
:当<Route>
产生嵌套时,渲染其对应的后续子路由。
示例代码
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/>,
children:[
{
path:'news',
element:<News/>
},
{
path:'message',
element:<Message/>
}
]
},
{
path:'/',
element:<Navigate to="/about"/>
}
]
pages/Home.jsx
import React from 'react';
import { NavLink, Outlet } from 'react-router-dom';
export default function Home() {
return (
<div>
<h2>Home组件内容</h2>
<div>
<ul className="nav nav-tabs">
<li>
<NavLink className="list-group-item" to="news">
News
</NavLink>
</li>
<li>
<NavLink className="list-group-item" to="message">
Message
</NavLink>
</li>
</ul>
{/* 指定Home组件下子路由组件的呈现位置 */}
<Outlet />
</div>
</div>
);
}
作用
:根据路由表,动态创建路由<Routes>
和<Route>
。
示例代码
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>
{/* 注册路由 */}
{element}
</div>
)
}
{/* element 等于下面的路由解构*/}
<Routes>
<Route path="/about" element={<About/>}></Route>
<Route path="/home" element={<Home/>}></Route>
{/* v6的Navigate替换了Redirect */}
<Route path="/" element={<Navigate to="/about" />}></Route>
</Routes>
作用
:获取当前匹配路由的params
参数,类似于5.x中的match.params
。
向路由组件传递params参数:
<Link to='/demo/test/tom/18'}>详情</Link>
<Route path="/demo/test/:name/:age" element={<Test/>} />
const {name,age} =useParams()
示例代码
routes/index.js
import Home from '../pages/Home';
import Message from '../pages/Message';
import Detail from '../pages/Detail';
import { Navigate } from 'react-router-dom';
export default [
{
path: '/home',
element: <Home />,
children: [
{
path: 'message',
element: <Message />,
children: [
{
path: 'detail/:id/:title/:content',
element: <Detail />,
},
],
},
],
},
{
path: '/',
element: <Navigate to="/about" />,
},
];
pages/Message.jsx
import React, { useState } from 'react';
import { Link, 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(m => {
return (
// 路由链接
<li key={m.id}>
<Link to={`detail/${m.id}/${m.title}/${m.content}`}>{m.title}</Link>
</li>
);
})}
</ul>
<hr />
{/* 指定路由组件的展示位置 */}
<Outlet />
</div>
);
}
pages/Detail.jsx
import React from 'react'
import {useParams,useMatch} from 'react-router-dom'
export default function Detail() {
const {id,title,content} = useParams()
//此处还可以使用useMatch() 返回当前匹配信息,对标5.x中的路由组件的`match`属性。
// const x = useMatch('/home/message/detail/:id/:title/:content')
return (
<ul>
<li>消息编号:{id}</li>
<li>消息标题:{title}</li>
<li>消息内容:{content}</li>
</ul>
)
}
作用
:返回当前匹配信息,对标5.x中的路由组件的match
属性。
示例代码
<Route path="/login/:page/:pageSize" element={<Login />}/>
<NavLink to="/login/1/10">登录</NavLink>
export default function Login() {
const match = useMatch('/login/:x/:y')
console.log(match) //输出match对象
//match对象内容如下:
/*
{
params: {x: '1', y: '10'}
pathname: "/LoGin/1/10"
pathnameBase: "/LoGin/1/10"
pattern: {
path: '/login/:x/:y',
caseSensitive: false,
end: false
}
}
*/
return (
<div>
<h1>Login</h1>
</div>
)
}
作用
:用于读取和修改当前位置的 URL 中的查询字符串。获取当前匹配路由的search参数
,类似于5.x中的location.search
。
向路由组件传递search参数:
路由链接(携带参数):<Link to='/demo/test?name=tom&age=18'}>详情</Link>
注册路由(无需声明,正常注册即可): <Route path="/demo/test" element={<Test/>}/>
接收参数:
//useSearchParams返回一个包含两个值的数组,内容分别为:当前的seaech参数、更新search的函数。
const {search,setSearch} =useSearchParams()
const name =search.get('name')
const id =search.get('id')
示例代码
routes/index.js
import Home from '../pages/Home';
import Message from '../pages/Message';
import Detail from '../pages/Detail';
import { Navigate } from 'react-router-dom';
export default [
{
path: '/home',
element: <Home />,
children: [
{
path: 'message',
element: <Message />,
children: [
{
path: 'detail/:id/:title/:content',
element: <Detail />,
},
],
},
],
},
{
path: '/',
element: <Navigate to="/about" />,
},
];
pages/Message.jsx
import React, { useState } from 'react';
import { Link, 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(m => {
return (
// 路由链接
<li key={m.id}>
<Link to={`detail?id=${m.id}&title=${m.title}&content=${m.content}`}> {m.title}
</Link>
</li>
);
})}
</ul>
<hr />
{/* 指定路由组件的展示位置 */}
<Outlet />
</div>
);
}
pages/Detail.jsx
import React from 'react'
import {useSearchParams,useLocation} 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')
//此处还可以使用useLocation()获取当前 location 信息,参数需要借助querystring解析,具体参考react router5中的内容。
const {search} = useLocation()
return (
<ul>
<li>
<button onClick={()=>setSearch('id=008&title=哈哈&content=嘻嘻')}>
点我更新一下收到的search参数
</button>
</li>
<li>消息编号:{id}</li>
<li>消息标题:{title}</li>
<li>消息内容:{content}</li>
</ul>
)
}
作用
:获取当前 location 信息,对标5.x中的路由组件的location
属性,可以接受search参数和state参数。
向路由组件传递state参数:
<Link to={{ pathname:'/demo/test', state:{name:'tom',age:18} }}>详情</Link>
<Route path="/demo/test" element={<Test/>}/>
const {state} = useLocation()
示例代码
import React from 'react'
import {useLocation} from 'react-router-dom'
export default function Detail() {
const x = useLocation()
console.log('@',x)
// x就是location对象:
/*
{
hash: "",
key: "ah9nv6sz",
pathname: "/login",
search: "?name=zs&age=18",
state: {a: 1, b: 2}
}
*/
return (
<ul>
<li>消息编号:{id}</li>
<li>消息标题:{title}</li>
<li>消息内容:{content}</li>
</ul>
)
}
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/Detail';
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',
element: <Detail />,
},
],
},
],
},
{
path: '/',
element: <Navigate to="/about" />,
},
];
pages/Message.jsx
import React, { useState } from 'react';
import { Link, 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(m => {
return (
// 路由链接
<li key={m.id}>
<Link
to="detail"
state={{
id: m.id,
title: m.title,
content: m.content,
}}
>
{m.title}
</Link>
</li>
);
})}
</ul>
<hr />
{/* 指定路由组件的展示位置 */}
<Outlet />
</div>
);
}
pages/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>
)
}
总结:向组件传递参数的方法及对应的Hooks
向组件传递参数的方法 | 接受参数对应的Hooks |
---|---|
传递params参数 | useParams()(推荐)或useMatch() |
传递search参数 | useSearchParams()或useLocation()(推荐) |
传递state参数 | useLocation()(推荐) |
作用
:返回一个函数用来实现编程式导航
。
push模式(默认):可以留下操作记录,不发生替换
replace模式:开启的路由不会留下操作记录,发生替换
示例代码
import React from 'react'
import {useNavigate} from 'react-router-dom'
export default function Demo() {
const navigate = useNavigate()
const handle = () => {
//第一种使用方式:指定具体的路径,第一个参数为跳转路径,第二个参数可以写replace跳转模式、state参数
//params参数和search参数直接拼在跳转路径中
navigate('/login', {
state: {a:1, b:2}
})
//第二种使用方式:传入数值进行前进或后退,类似于5.x中的 history.go()方法
navigate(0)
//navigate(-1)
//navigate(1)
}
return (
<div>
<button onClick={handle}>按钮</button>
</div>
)
}
作用
:如果组件在 <Router>
的上下文中呈现,则 useInRouterContext
钩子返回 true,否则返回 false。第三方组件的封装者想知道别人是不是在路由环境下使用你的组件,可以借助这个Hook
示例代码
App.jsx
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter} from "react-router-dom";
ReactDOM.render(
<BrowserRouter>
{/*App组件被路由组件<BrowserRouter>包裹,那么App组件及其子组件都处于<Router> 的上下文中 */}
<App/>
</BrowserRouter>,root
);
pages/Home.jsx
import { Link,useInRouterContext } from "react-router-dom";
function Home() {
//打印一下useInRouterContext
console.log(useInRouterContext())//true
return (
<div>
<Link to="/路径">按钮</Link>
</div>
);
}
作用
:返回当前的导航类型(用户是如何来到当前页面的)。
返回值
:POP、PUSH、REPLACE(这三种值代表是通过何种方式跳转到页面的)。
POP
:在浏览器中直接打开了这个路由组件(刷新页面)PUSH
:可以留下操作记录,不发生替换REPLACE
:开启的路由不会留下操作记录,发生替换示例代码
pages/Home.jsx
import React from 'react';
import { NavLink, Outlet } from 'react-router-dom';
export default function Home() {
return (
<div>
<h2>Home组件内容</h2>
<div>
<ul className="nav nav-tabs">
<li>
<NavLink className="list-group-item" replace to="news">
News
</NavLink>
</li>
<li>
<NavLink className="list-group-item" to="message">
Message
</NavLink>
</li>
</ul>
{/* 指定路由组件呈现的位置 */}
<Outlet />
</div>
</div>
);
}
pages/News.jsx
import React from 'react'
import {useNavigationType} from 'react-router-dom'
export default function News() {
//打印跳转类型 点击Home组件的第一个链接 打印REPLACE 点击第二个链接打印 PUSH
console.log(useNavigationType())
return (
<ul>
<li>news001</li>
<li>news002</li>
<li>news003</li>
</ul>
)
}
作用
:用来呈现当前组件中渲染的嵌套(子)路由。
示例代码
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/>,
children:[
{
path:'news',
element:<News/>
},
{
path:'message',
element:<Message/>
}
]
},
{
path:'/',
element:<Navigate to="/about"/>
}
]
pages/Home.jsx
import React from 'react';
import { NavLink, Outlet, useOutlet } from 'react-router-dom';
export default function Home() {
console.log( useOutlet());
// 如果嵌套路由没有挂载,则result为null
// 如果嵌套路由已经挂载,则展示嵌套的路由对象
return (
<div>
<h2>Home组件内容</h2>
<div>
<ul className="nav nav-tabs">
<li>
<NavLink className="list-group-item" replace to="news">
News
</NavLink>
</li>
<li>
<NavLink className="list-group-item" to="message">
Message
</NavLink>
</li>
</ul>
{/* 指定路由组件呈现的位置 */}
<Outlet />
</div>
</div>
);
}
作用
:给定一个 URL值,解析其中的:path、search、hash值。
示例代码
pages/News.jsx
import React from 'react'
import {useNavigationType,useResolvedPath} from 'react-router-dom'
export default function News() {
console.log('@@',useResolvedPath('/user?id=001&name=tom#qwe'))
// {pathname:'/user',search:'?id=001&name=tom',hash:'#qwe'}
return (
<ul>
<li>news001</li>
<li>news002</li>
<li>news003</li>
</ul>
)
}