美文网首页
React-Router的理解与实现

React-Router的理解与实现

作者: 吴晗君 | 来源:发表于2019-07-13 16:05 被阅读0次

    前端两种路由方案

    1. 无hash
      通过h5的pushState、replaceState、go、forward、back配合onpopstate来处理。注意pushState无法进入popstate事件。pushState兼容到ie10。
      pushState是如何处理路由的?是实现一个onpushstate事件,然后重写pushstate方法,在每次调用pushState的时候该事件。
    2. 有hash
      传统方式,改变window.location.hash配合onhashchange事件来渲染页面内容。onhashchange兼容ie8及以上,ie8以下用setInterval监测hash。

    相关正则

    1. (?:)表示当前捕获组会匹配但是不会被拿到匹配结果中。这在使用或字符“(|)”来组合一个模式的各个部分是很有用。例如“industr(?:y|ies)”就是一个比“industry|industries”更简略的表达式。
    2. yyy(?=xxx)表示匹配后面为xxx的yyy。名字叫前瞻。
    3. yyy(?!xxx)表示匹配后面不为xxx的yyy。名字叫负前瞻。

    path-to-regexp工具库

    这个库很多前端框架都在用,来匹配路由。比如vuereactkoaexpress

    let pathToRegExp = require('path-to-regexp');
    let regx = pathToRegExp('/home',[],{end:true});
    console.log(regx);//   /^\/home\/?$/i /^\/home(?:\/)?$/i
    
    image.png

    匹配两种情况

    1. /home开头,以/结尾。
    2. /home开头并结尾。
    let regx2 = pathToRegExp('/home',[],{end:false});
    console.log(regx2);//   /^\/home\/?(?=\/|$)/i /^\/home(?:\/(?=$))?(?=\/|$)/i
    
    image.png-w150

    匹配三种情况

    1. /home开头,以/结尾。
    2. /home开头并结尾。
    3. /home开头,字母e后面是/的,\后面任意个数字符。

    keys

    let keys =  []
    let regx2 = pathToRegExp('/home/:id/:name',keys,{end:false});
    const [url, ...groups] = path.match(regx2)
    console.log(a)
    

    这个keys比较重要,用来拿到对应的分组名id和name,result中groups就可以一一对应起来,作为routerContext中match.params的值。

    Router.js(HashRouter、BrowserRouter)

    这个类组件目的是为了拿到window.location的信息,并且进行监听对应hashchange事件。更新路由信息。通过react.context api使得全局都可以访问。

    Route.js

    这个类组件的目的是根据传进来的参数来渲染组件,比如path(匹配哪个路由)、exact(是否精确)、component(渲染什么组件)。

    React-Router route渲染对应的组件可以拿到的props

    image.png

    当用户输入了一个错误的路由,或者点击一级路由的时候,需要显示一个默认的子路由,这时候怎么办呢?

    需要SwitchRedirect组件来配合实现。
    Switch组件依此遍历自己的所有children,如果匹配,则渲染对应route,Redirect不需要传path,在Switch组件中,path默认值为'/',且exact为false。如果其他都不匹配,则渲染Redirect to属性对应组件。

    当希望实现是否登陆校验,跳转登陆页面,路由该怎么写呢?

    <Route path='/' render={(props) => (is_logined ? <Dashboard {...props} /> : <Redirect to="/login"/>)}/>
    

    在Router组件内可以判断,props.render是否是个函数,如果是个函数,则执行并拿到对应组件进行渲染。

    当希望实现是否登陆校验,跳转登陆页面,路由该怎么写呢?

    <Route path='/' render={(props) => (is_logined ? <Dashboard {...props} /> : <Redirect to="/login"/>)}/>
    

    在Router组件内可以判断,props.render是否是个函数,如果是个函数,则执行并拿到对应组件进行渲染。

    withRouter是什么?

    是个高阶组件,用该组件包裹后可以拿到路由参数。内部实现就是用的react.context。注意还能拿到被包装组件到ref。
    下面这段话是在幕课搜到的。

    其次withRouter是专门用来处理数据更新问题的。在使用一些redux的的connect()或者mobx的inject()的组件中,如果依赖于路由的更新要重新渲染,会出现路由更新了但是组件没有重新渲染的情况。这是因为redux和mobx的这些连接方法会修改组件的shouldComponentUpdate

    在使用withRouter解决更新问题的时候,一定要保证withRouter在最外层,比如withRouter(connect(Component))

    Prompt的实现思路?

    Prompt常用于用户大量输入文本,不消息按错跳出页面的情况。
    在组件内使用

    <Prompt
       when={isBlocking}
       message={location=>`你确定要跳转到${location.pathname}吗?`}
    />
    

    isBlocking是当前组件自己setState的值,每次改变后重新渲染Prompt组件,在Prompt组件内调用ReactRouterContext中history.block方法。改变当前是否需要提示用户的状态(就是个存放在HashRouter或者BrowserRoot中的变量)。然后在监听hashchange的地方判断是否需要提醒用户。

    BrowserRouter的实现思路?

    和HashRouter没有区别,唯一区别是,hashRouter可以直接监听hashchange事件,而h5的pushSate方法没有原生事件可以监听,需要自己重写pushstate,就是在调用原生pushstate前调用一个函数(监听函数),这样就模拟了事件触发。

    参考

    阮一峰#
    两种路由介绍
    minrouter
    jquery.pjax.js
    pjax相关文章
    history.js

    相关文章

      网友评论

          本文标题:React-Router的理解与实现

          本文链接:https://www.haomeiwen.com/subject/afnahctx.html