本篇简述了react-router-dom的原理,其中也包含了一下 react-router-dom的一些简单用法,希望能方便大家理解!
定义:实现根据不同路径渲染不同的组件
有两种实现方式:
HashRouter :利用监听hash变化(有一个事件hashchange)实现路由切换,它是路由容器,渲染子组件,并向下层子组件传递(Context上下文传递)loaction,history等路由信息
window.addEventListener(‘hashchange’,()=>{window.location.hash})
BrowserHistory :利用H5Api实现路由切换,是路由容器,渲染子组件,并向子组件传递loaction,history等路由信息
history对象提供了操作浏览器会话历史的接口
原理是利用window.onpushstate方法和window.onpopstate方法,当向浏览器地址栏中添加条目(window.history.pushState())和点击浏览器的前进后退按钮会改变路由信息
window.history.pushState(state,title,url) 向浏览器历史条目中添加一条记录 不会触发事件 所以后面需要自己重写pushState方法和模拟写一个onpushstate方法 用来监听pushState 进而触发这个onpushstate方法
!(function(history) {
let oldPushState = history.pushState //缓存老的pushState方法
history.pushState = function(state, title, url) {
if (typeof window.onpushstate === 'function') {
window.onpushstate(state, title, url)
}
oldPushState.call(history, state, title, url)
}})(window.history)
window.onpopstate=function(){} 只会在浏览器的某些行为下触发,比如点击后退、前进按钮(或者在JavaScript中调用history.back()、history.forward()、history.go()方法)
Route:是路由规则 ,当path和浏览器地址栏url匹配则显示组件, 一般有两个属性path和component, exact 是精确匹配 (exact决定是否要精确匹配 isExact有没有精确匹配到)
Route渲染组件有三种方式:
- component 最简单 但是不能加逻辑判断
- render 是一个函数 可以加逻辑判断 会渲染render执行后的返回值
component和render都有一个共同点就是当path跟地址栏路径匹配才会渲染
3.children 也是一个函数 但是它不管路径是否匹配都会渲染children执行后的返回值
实现:
export default class Route extends React.Component {
static contextType = RouterContext
render() {
let paramsName = []
let { pathname } = this.context.location;
let { path="/", component: RouteComponent, exact = false ,render,children} = this.props
let regexp = pathToRegExp(path, paramsName, { end: exact })
paramsName = paramsName.map(item => item.name)
let matched = pathname.match(regexp)
let routeProps={
location:this.context.location,
history:this.context.history,
}//路由信息
if (matched) {//匹配到了
let [url,...values]=matched;
let params=values.reduce((memo,cur,index)=>{
memo[paramsName[index]]=cur
return memo
},{})//{id:1}
let match={
url,
params,
path,
isExact:pathname===url
}
routeProps.match=match
if(RouteComponent){
return <RouteComponent {...routeProps}/>
}else if(render){
return render(routeProps)
}else if(children){
return children(routeProps)
}else{
return null
}
} else {//没有匹配到
if(children){
return children(routeProps)
}else{
return null
}
}
}
}
通过Route渲染出来的组件内部都有路由信息(history,location, match)
没有通过Route渲染出来的组件想要获取路由信息可以用 withRoute包装
Link: 提供导航链接 原理使用history.push(props.to)
属性 to:string
to:object
<li className="list-group-item" key={item.id}>
<Link to={{ pathname: `/user/detail/${item.id}`, state: item }}>{item.username}
</Link>
</li>
在detail组件中打印props 取props.location.state 就可以拿到当前对象的值 state - 存储到 location 中的额外状态数据 hashRouter一刷新就没有了变成undefined
实现:
<RouterContext.Consumer>
{
routerValue => {
return <a {...props} onClick={()=>routerValue.history.push(props.to)}>{props.children}</a>
}
}
</RouterContext.Consumer>
Switch:渲染跟路径匹配的第一个子<Route>或<Redirect> (跟js中switch case的意义一样)
Redirect:重定向 会导航到一个新的位置,新的位置将覆盖历史堆栈中的当前条目
属性:to:string 要重定向到的URL
<Redirect to=”/home/me” />
to:object 要重定向的位置,其中pathname就是要重定向到的url,state里面可以携带信息
<Redirect to={{pathname:'/login',state:{path:path}}}/>
from:string只有访问from提供的url 才能重定向到to指定的url
<Redirect from=’/home’ to=”/” />
实现:
export default (props) => {
let routerValue = useContext(RouterContext)
let pathname = routerValue.location.pathname;
if (!props.from || (props.from && props.from === pathname)) {
routerValue.history.push(props.to)
}
return null
}
NavLink:
可以有exact属性 原理是当to的属性跟地址栏路径匹配 则给组件加一个active类名
实现:
export default (props) => {
let { to, children, exact } = props
return <Route
exact={exact}
path={to}
children={(routerProps) => {
return <Link
className={routerProps.match ? 'active' : ''}
to={to}>{children}
</Link>
}
} />
}
withRouter:
高阶组件withRouter作用是当一个自定义的组件没有通过Route组件渲染,但是想获取location,history,math等属性 那么就可以用withRoute包裹进而获取location,history,match这些属性
实现:
export default (OldComp)=>{
return props=>{
return <Route render={routerProps=>(<OldComp {...props} {...routerProps}/>)}/>
}
}
路由传参:
- State :HashRouter刷新页面参数会丢失 BrowserRouter刷新不会丢失
<Route path="/user/detail" component={UserDetail} /> <Link to={{ pathname: '/user/detail', state: item }}>{item.username}</Link> 跳转:props.history.push({ pathname: '/user/detail', state: item })
取参数用props.location.state
- params:HashRouter和BrowserRouter刷新页面参数都不会丢失
<Route path="/user/detail/:id" component={UserDetail} /> <Link to={`/user/detail/${item.id}`}>{item.username}</Link> 跳转props.history.push({ pathname: '/user/detail/'+item.id})
取参数props.match.params
- query:HashRouter和BrowserRouter刷新页面参数都会丢失
<Route path="/user/detail" component={UserDetail} /> <Link to={{ pathname: '/user/detail', query: item }}>{item.username}</Link> 跳转props.history.push({pathname:'/user/detail',query:item})
获取参数:props.location.query 刷新页面的时候就找不到了
优缺点总结:
params:在HashRouter和BrowserRouter路由中刷新页面参数都不会丢失
state:在BrowserRouter中刷新页面参数不会丢失,在HashRouter路由中刷新页面会丢失
query:在HashRouter和BrowserRouter路由中刷新页面参数都会丢失
好了~暂时我的理解就这些,后续还会补充的,有问题可以留言哦