简述react-router-dom原理

本篇简述了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渲染组件有三种方式:

  1. component 最简单 但是不能加逻辑判断
  2. 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}/>)}/>
  }
}

路由传参:

  1. 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

  2. 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

  3. 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路由中刷新页面参数都会丢失

好了~暂时我的理解就这些,后续还会补充的,有问题可以留言哦

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值