路由单页面应用(SPA)的优点?
- 整个应用只有一个完整的页面,多组件
- 点击页面中的链接不会刷新页面,只会页面局部刷新
- 数据通过Ajax请求,在页面异步展示
路由的理解
- 一个路由就是一个映射关系(key: value)
- key是路径,value可能是function(node)或component
React-router-dom API介绍
HashRouter 和 BrowserRouter
路由器,用来全局包裹路由和路由链接
<HashRouter>
<app/>
</HashRouter>
两者区别:
-
底层原理不一样:
BrowserRouter 使用的h5 的API,不兼容IE9以下
HashRouter 使用的是URL的hash值
-
url 的形式不一样
BrowserRouter 路径中没有
#
HashRouter 路径中包含
#
-
刷新后对路由state参数有影响
BrowserRouter 没有任何影响,因为state存在history的对象中
HashRouter 刷新页面后导致state参数消失
声明式路由
Link
靠路由链接实现组件切换 -- 编写路由
跳转模式:
- push
- replace
<BrowserRouter>
<Link to="/home" replace>Home</Link>
<Link to="/about">About</Link>
</BrowserRouter>
link 相当于 a 链接标签
Route
注册路由,也就是展示路由的地方
<Route path='/home' exact component={Home}></Route>
<Route path='/about' component={About}></Route>
<Route path='/refExc' component={RefExc}></Route>
路由组件 和 一般组件
路由组件
靠路由匹配展示组件界面
一般组件
两者最大的区别传递信息:
- 一般组件通过 props
- 路由组件 传递消息的三个属性 history location match
NavLink
当它匹配当前的URL时,它会处于激活状态的链接样式。
<NavLink to="/about">About</NavLink>
封装一个 MyNavLink
:
import {NavLink} from 'react-router-dom'
function MyNavLink(props) {
return (
<NavLink
activeStyle={{backgroundColor: '#f60', color: '#fff'}}
{...props}>{props.children}
</NavLink>
)
}
export default MyNavLink
Switch
从上往下只匹配一个符合 path
的路由,匹配到之后,下面的不在匹配。
注意:超过两个以上的路由使用。
路由的模糊匹配和严格匹配
模糊匹配
<>
<div>
<MyNavLink to="/home">Home</MyNavLink>
<MyNavLink to="/about/a/b">About</MyNavLink> // 这样写的时候还是能匹配到 /about
<MyNavLink to="/refExc">refExc</MyNavLink>
</div>
<div>
<Switch>
<Suspense fallback={<Loading />}>
<Route path='/home' exact component={Home}></Route>
<Route path='/about' component={About}></Route>
<Route path='/refExc' component={RefExc}></Route>
<Redirect to="/home" />
</Suspense>
</Switch>
</div>
</>
严格匹配
<Route exact path='/about' component={About}></Route>
添加关键字,exact
之后,只有当 path
完全相同时,才能匹配路由,开启之后将无法匹配二级路由
Redirect 重定向
语法:<Redirect to="/home" />
<Switch>
<Suspense fallback={<Loading />}>
<Route path='/home' exact component={Home}></Route>
<Route exact path='/about' component={About}></Route>
<Route path='/refExc' component={RefExc}></Route>
<Redirect to="/home" />
</Suspense>
</Switch>
当没有匹配到响应理由时,就会根据 Redirect 去到响应的路由。
嵌套路由
二级路由展示:
import { lazy } from 'react'
import {Route, Switch, Redirect} from 'react-router-dom'
import MyNavLink from '../../components/MyNavLink'
const News = lazy(() => import('./news')) // 路由懒加载
const Message = lazy(() => import('./message'))
function Router() {
return (
<>
<MyNavLink to="/router/news">News</MyNavLink>
<MyNavLink to="/router/message">message</MyNavLink>
<Switch>
<Route path="/router/news" component={News} />
<Route path="/router/message" component={Message} />
<Redirect to="/router/news" />
</Switch>
</>
)
}
export default Router
/router/news
先对以及路由 router
进行模糊匹配,然后在对二级路由匹配。一级路由不能开启严格模式
路由传参
params 传参
地址栏上直接以参数的形式展示
传递:
<MyNavLink to={`/router/news/${user.id}/${user.name}`}>News</MyNavLink>
声明接收参数 id和name:
<Route path="/router/news/:id/:name" component={News} />
接收:match
取出params
中的参数
import { Fragment } from "react";
function News(props) {
const {id, name} = props.match.params
return (
<Fragment>
<h2>我是新闻</h2>
<p>{id}---{name}</p>
</Fragment>
)
}
export default News
search 参数
地址栏上以 ?id=01&name=zhangsan
的形式
传递:
<MyNavLink to={`/router/message?id=${user.id}&name=${user.name}`}>message</MyNavLink>
Route
不需要接收
接收:
search在props.location中
import qs from 'querystring'
function Message(props) {
const {search} = props.location
const {id, name} = qs.parse(search.slice(1))
return (
<>
<h2>我是消息</h2>
<p>{id}---{name}</p>
</>
)
}
export default Message
state 参数
地址栏上没有展示,但是刷新页面参数不丢失
传递:
<MyNavLink to={{pathname: '/router/chat', state:{id: user.id, name: user.name}}}>chat</MyNavLink>
Route
不需要处理
接收:
function Chat(props) {
const {id, name} = props.location.state || {}
return (
<>
<h2>我是微信</h2>
<p>{id}---{name}</p>
</>
)
}
export default Chat
编程式路由导航
push 和 replace 常用两种模式:
- push:一种进栈出栈的模式,可以返回上一个路由
- replace:一种替换路由的方式,不能返回
使用编程式路由跳转并传递参数:
import { useState, lazy } from 'react'
import {Route, Switch} from 'react-router-dom'
const Message = lazy(() => import('./message'))
const Chat = lazy(() => import('./chat'))
function Router(props) {
const [user] = useState(
{id: 1, name: 'zhangsan'}
)
// search参数形式
const pushMessage = (id, name) => {
props.history.push(`/router/message?id=${id}&name=${name}`)
}
// state 参数形式
const repalceChat = (id, name) => {
props.history.replace('/router/chat', {id, name})
}
return (
<>
<button onClick={() => pushMessage(user.id, user.name)}>push进入message</button>
<button onClick={() => repalceChat(user.id, user.name)}>replace进入chat</button>
<Switch>
<Route path="/router/message" component={Message} />
<Route path="/router/chat" component={Chat} />
</Switch>
</>
)
}
export default Router
扩展
withRouter
React 分为一般组件和路由组件,在一般组件的props中并没有history,所以一般使用 withRouter 包裹组件,使组件的props中拥有history。