React-router
React Router现在的版本是6,使用方式相对于之前版本的思想有所不同。之前版本的思想是传统的思想:路由应该统一在一处渲染, Router 4之后是这样的思想:一切皆组件
React Router包含了四个包:
包名 | Description |
---|---|
react-router | React Router核心api |
react-router-dom | React Router的DOM绑定,在浏览器中运行不需要额外安装react-router |
react-router-native | React Native 中使用,而实际的应用中,其实不会使用这个。 |
react-router-config | 静态路由的配置 |
主要使用react-router-dom
1.使用方式
- Route组件的exact属性
exact
属性标识是否为严格匹配, 为true
是表示严格匹配,为false
时为正常匹配。
- Route组件的render属性而不是component属性
怎么在渲染组件的时候,对组件传递属性呢?使用component
的方式是不能直接在组件上添加属性的。所以,React Router的Route
组件提供了另一种渲染组件的方式 render
, 这个常用于页面组件级别的权限管理。
-
路由的参数传递与获取
-
Switch组件
总是渲染第一个匹配到的组件
-
处理404与默认页
-
withRoute高阶组件的使用
-
管理一个项目路由的方法
-
HashRouter和BrowserRouter的区别,前端路由和后端路由的区别。
2.React Router基本原理
React Router甚至大部分的前端路由都是依赖于history.js
的,它是一个独立的第三方js库。可以用来兼容在不同浏览器、不同环境下对历史记录的管理,拥有统一的API。
- 老浏览器的history: 通过
hash
来存储在不同状态下的history
信息,对应createHashHistory
,通过检测location.hash
的值的变化,使用location.replace
方法来实现url跳转。通过注册监听window
对象上的hashChange
事件来监听路由的变化,实现历史记录的回退。 - 高版本浏览器: 利用HTML5里面的history,对应
createBrowserHistory
, 使用包括pushState
,replaceState
方法来进行跳转。通过注册监听window
对象上的popstate
事件来监听路由的变化,实现历史记录的回退。 - node环境下: 在内存中进行历史记录的存储,对应
createMemoryHistory
。直接在内存里push
和pop
状态。
3.React-router-dom@5
Route
import { BrowserRouter, Route} from 'react-router-dom'
export default function App() {
return (
<BrowserRouter>
<Route path='/a'>A组件</Route>
<Route path='/b'>B组件</Route>
</BrowserRouter>
)
}
通过Route组件来进行组件的显示 path为显示相应组件的url路径
Route组件必须在BrowserRouter组件内使用
Switch
Switch组件会在路径匹配到第一个路由后停止 不会一次匹配多个路由
import { BrowserRouter, Route, Switch} from 'react-router-dom'
export default function App() {
return (
<BrowserRouter>
<Switch>
<Route path='/a'>A1组件</Route>
<Route path='/a'>A2组件</Route>
<Route path='/b'>B组件</Route>
</Switch>
</BrowserRouter>
)
}
exact属性
// 路由匹配为模糊匹配 只要Url路径中包含路由路径 都会进行匹配显示
// 为Route组件添加exact属性来精确匹配
<Route path='/a' exact={ true }>A1组件</Route>
Redirect
Redirect组件能实现路由重定向
<Route path='/e'>
<Redirect to='/a' />
</Route>
// 将Url路径中的路由path换成 Redirect中的to路径
路由显示组件的三种方式
路由的设置方式
<Route path='/c' render={ ()=>< Cp1 /> } />
<Route path='/c' component={ Cp1 } />
<Route path='/c' > < Cp1 /> </Route>
跳转的设置方式
<Link to={{
pathname:'/d',
search:'?a=1&b=2',
hash:'abc',
state:{ a:1, b:2 }
}}>跳转方式1</Link>
<Link to='/c'>跳转方式2</Link>
<Link to={ () => '/c' }>跳转方式3</Link>
link标签也必须在BrowserRouter组件内
通过to传入对象参数的方式只能在<Route path='/c' component={ Cp1 } />
跳转的组件中获取
Navlink是Link的一个特定版本
会在匹配上当前的url的时候给已经渲染的元素添加参数,Link与Navlink的区别:两者都是实现路由的跳转
但点击Link时,url会更新,组件会被重新渲染,但是页面不会重新加载…使用to链接组件时,它的值既可是字符串,也可以是location对象(包含pathname、search、hash、与state属性)如果其值为字符串,将会被转换为location对象
function Cp1(loc) {
console.log(loc); // loc获取到link的to传入的对象
return (
<div>app</div>
)
}
<Route path='/c' > < Cp1 /> </Route>
路径跳转的组件不能接受props传入参数对象
<Route path='/c' render={ ()=>< Cp1 /> } />
路径跳转的组件传递参数的方式为
<Route path='/c' render={ ({match, location, history})=>{
console.log(match, location, history);
return < Cp1 />
} } />
// render函数形参为一个对象 从中解构出match location history路由对象
// 形参方式无法传入组件内部 可以结合props传入组件
<Route path='/c' render={ (match, location, history)=>{
console.log(match, location, history);
return < Cp1 location={location} match={match} history={history} />
} } />
动态路由
<Route path='/e/:abc' component={ Cp2 } />
// 设置 :变量 的方式接收动态参数
路由拦截
<Route path='/center' render={()=>{
return isAuth()?<Center/>:<Redirect to="/login" />
}} />
通过三目运算符逻辑判断显示组件或是重定向
函数组件中获取路由对象
通过hooks获取路由对象
import { useHistory, useLocation, useParams } from 'react-router-dom'
const Cp3 = ()=> {
const history = useHistory()
const location = useLocation()
const params = useParams()
return (
<div>Cp3</div>
)
}
类组件中获取路由对象
通过withRouter组件
import { Component } from 'react'
import { withRouter } from 'react-router-dom';
class Cp4 extends Component {
constructor(props){
super(props)
console.log(this.props);
}
render() {
return (
<div>Cp4</div>
)
}
}
export default withRouter(Cp4)
// 类组件中通过暴露时调用 withRouter函数 能强制让类组件 通过props来获取路由参数
history对象及路由栈
每次路由跳转时会在路由栈中存入路由数据 使用浏览器前进后退按钮即可在路由栈中相对应进行切换
history对象方法
history.push() 在路由栈后添加一条数据并跳转
history.push('/a')
history.push({
pathname:'/a',
search:'?a=1&b=1231',
state:{}
})
history.replace() 替换路由栈中的最后一条数据并跳转
history.replace({
pathname:'/a',
search:'?a=1&b=1231',
state:{}
})
history.goBack() 加载路由栈中的前一个Url
history.goBack()
路由的应用
在实际开发中需要将路由抽离出来
import { Route } from 'react-router-dom'
import Cp1 from './Cp1'
import Cp2 from './Cp2'
import Cp3 from './Cp3'
import Cp4 from './Cp4'
import Cp5 from './Cp5'
// 将路由放到数组中进行遍历渲染成Route组件
const routes = [
{ name:'home', path:'/home', component: Cp1 },
{ name:'list', path:'/list', component: Cp2 },
{ name:'detil', path:'/detail', component: Cp3 },
{ name:'me', path:'/uc', component: Cp4 },
{ name:'login', path:'/login', component: Cp5 }
]
const Routers = ()=> {
<>
<Route exact={true} path='/'> // 添加首页重定向路由
<Redirect to='/home' />
</Route>
{ routes.map(item => <Route path={ item.path } component={ item.component } />) }
<Route path='*'> // 通配符 当匹配不到路径的时候显示404
404
</Route>
</>
}
export default Routers // 将渲染完成后路由组件暴露 放到根组件的BrowserRouter组件内的Switch组件中
注:
props传入的参数和search传入的参数以及state的参数在页面刷新后仍然存在
当重新打开页面后state会失效 props传入的参数和search传入的参数仍然有效
URLSearchParams
浏览器原生类 用于处理search参数
// 通过URLSearchParams对路由中search传递来的参数进行处理
const query = new URLSearchParams(props.location.search)
// 处理后的对象通过 对象.get()方法获取值
const c = query.get('c')
const d = query.get('d')