1.安装
yarn add react-router-dom@5.3.0
2. react-router-dom 这个包提供了三个核心的组件
import { HashRouter, Route, Link } from 'react-router-dom'
3.使用 HashRouter 包裹整个应用,一个项目这只会有一个 Router
<HashRouter>
<div className="App">App</div>
</HashRouter>
4.使用Link 指定导航链接
<Link to="/first">页面一</Link>
<Link to="/two">页面二</Link>
5. 使用 Router 指定路由规则
// 在哪里写的 Route,最终匹配到的组件就会渲染到哪里
<Route path='/first' component={First}></Route>
App.js
import React from 'react'
import { HashRouter, Link, Route } from 'react-router-dom'
import Home from './pages/Home'
import Search from './pages/Search'
import Comment from './pages/Comment'
export default function App() {
return (
<HashRouter>
<div>
<ul>
<li>
<Link to='/home'>首页</Link>
</li>
<li>
<Link to='/search'>搜索</Link>
</li>
<li>
<Link to='/comment'>评论</Link>
</li>
</ul>
<hr />
<Route path='/home' component={Home} />
<Route path='/search' component={Search} />
<Route path='/comment' component={Comment} />
</div>
</HashRouter>
)
}
Router 详细说明
- 常有两种 Router : HashRouter 和 BrowserRouter , 用来包裹整个应用,一个 React 应用只需要使用一次
- HashRouter : 使用 URL 的哈希值实现 (
http://localhost:3000/#/first
),是通过监听 window 的hashchange
事件来实现的。 - BrowserRouter :使用 H5 的 history API 实现 (
http://localhost:3000/first
),是通过监听 window 的popstate
事件来实现的。
// 使用时建议通过 as 起一个别名,方便修改
import { HashRouter as Router, Route, Link } from 'react-router-dom'
路由的执行过程
- 点击Link 组件 ,浏览器地址栏中的url 发送变化
- ReactRouter 通过 hashchange 或 popState 监听到了地址栏 url 变化
- ReactRouter 内部遍历所有 Route 组件,使用路由规则(path) 与 pathname(hash) 进行匹配
- 当路由规则(path)能够匹配地址栏中的 pathname(hash)时,就展示 Router 对于的组件
Link 与 NavLink
- Link 组件最终会渲染成 a 标签 ,用于指定路由导航
- a,to 属性,将来会渲染成 a 标签的 href 属性
- b,Link 组件无法实现导航的高亮效果
- NavLink 组件,一个更特殊的Link 组件,可以用于指定当前导航高亮
- a,to:用于指定地址,会渲染成 a 标签的href 属性
- b,activeClass:用于指定高亮的类名,默认为 active
- c,exact:精确匹配,表示必须精确匹配类名才能应用 calss,默认是模糊匹配
App.js
,<Link></Link>
改成了 <NavLink></NavLink>
组件,to 对应的值改成了 /
,同时出口 Route 组件的 path 属性也改成了 /
,代码如下。
import React from 'react'
import { HashRouter, Route, NavLink } from 'react-router-dom'
import Home from './pages/Home'
import Search from './pages/Search'
import Comment from './pages/Comment'
export default function App() {
return (
<HashRouter>
<div>
<ul>
<li>
<NavLink to='/'>首页</NavLink>
</li>
<li>
<NavLink to='/search'>搜索</NavLink>
</li>
<li>
<NavLink to='/comment'>评论</NavLink>
</li>
</ul>
<hr />
<Route path='/' component={Home} />
<Route path='/search' component={Search} />
<Route path='/comment' component={Comment} />
</div>
</HashRouter>
)
}
问题:点击搜索发现首页也应用了激活的 class 类名。
// 以 / 开头的,就会被添加 class,当访问 /search 的时候,发现是以 / 开头的,所以这里也加了 class
<NavLink to='/'>首页</NavLink>
解决方法。
// 必须是 / 才会被加 class
<NavLink exact to='/'>
首页
</NavLink>
Route 匹配规则
{
/* 默认是以 '/' 开头的路径就会被匹配到组件,添加 exact 属性可以开启精确匹配 */
}
;<Route path='/' exact component={Home}></Route>
- 默认情况下,path 为 / 能够匹配所有路由组件,因为所有路由组件都是以 / 开头的,一般来说,如果路径配置了 / 往往都需要配置 exact 属性
- 如果 path 的路径上匹配上了,那么对于的组件就会被 render,否则就会 render null
- 如果没有指定 path 那么一定会被渲染,例如
<Route component={NotFound}></Route>
。
Switch 与 404
- 通常,会把一个个的 Router 包裹在一个 Switch 组件中 ,这样只会渲染第一个匹配的组件,往往是我们期望的
- 通过 Switch 组件配合不带 path 属性的 Router 组件 能实现 404 效果,即便不需要实现 404,也可以使用Switch 包裹来提升性能
<Switch>
<Route exact path='/' component={Home} />
<Route path='/about' component={About} />
<Route path='/user' component={User} />
<Route component={NotFound} />
</Switch>
编程式导航
- 编程式导航:通过 JS 代码来实现页面跳转,可以处理相关逻辑,更加灵活
- 第一种方式 通过 props 拿到 history 进行 跳转,props.history.push( ' /comment' )
- 第二种方式 通过 react-router-dom 提供的 useHistory 钩子进行跳转
import React from 'react'
import { useHistory } from 'react-router-dom'
export default function Search(props) {
const history = useHistory()
const handleClick = () => {
history.push('/comment')
}
return (
<div>
<h3>Search</h3>
<button onClick={handleClick}>click</button>
</div>
)
}
动态路由传参
1.入口传参
<NavLink to='/user/111'>用户111</NavLink>
<NavLink to='/user/222'>用户222</NavLink>
2.出口匹配
<Route path='/user/:id' component={User} />
3.组件中接收
import React from 'react'
import { useParams } from 'react-router-dom'
export default function User(props) {
const params = useParams()
return (
<div>
<h2>User</h2>
<p>props 获取参数: {props.match.params.id}</p>
<p>useParams 获取参数: {params.id}</p>
</div>
)
}