• React-router总结


    版本

    v3和v4有一些差距:

    https://blog.csdn.net/qq_35484341/article/details/80500237

    以下的总结,都是基于V4的

    官方文档:https://reacttraining.com/react-router/web/guides/quick-start

    核心组件和用法

    <BrowserRouter/>   
    <HashRouter/>
    <Route/>
    <Switch/>
    <Redirect/>
    <Link/> (<NavLink/>)
    withRouter

    不多解释,先上实例:

    <BrowserRouter>
       <Link to="/">主页</Link>
       <Link to="/recommend">推荐</Link>
       <Link to="/detail/1">详情</Link>
    
       <Route path="/" exact component={Home}/>
       <Route path="/detail/:id" exact component={Detail}/>
       <Route path="/recommend" exact component={Recomm}/>
    </BrowserRouter>

    BrowserRouter和HashRouter

    这两者可以理解为路由的作用域,所有的Link组件和Route组件都必须在其内部。

    浏览器路由和哈希路由的区别:

    • BrowserRouter中的URL指向真实的url,当页面刷新(或直接操作url并回车)时,将产生指向该路径的url请求,如果服务器端没有配置该路径,则返回404。在项目上线后,需要我们去配置服务端。(通过Link并不会向后端发送真实请求)
    • HashRouter中#后面的uri并不是真实的请求路径,对于后端来说,全都指向同一个地址。另外哈希历史记录不支持loaction.key和loaction.state,当通过state传递参数的时候,无法从历史记录中获取到,可能会导致页面显示异常。

    在BrowserRouter模式下,如何在服务端配置呢?

    • Nginx配置(前端项目打包),将任何URL访问都指向index.html
    • 后端服务配置(前端项目打包),将任何URL访问都指向index.html
    • 开启前端服务(需要进行Nginx反向代理)

    Link

    被渲染成a标签,跟href属性的所用类似。点击Link标签和a标签,看到的效果是一样的,但我们推荐<Link>,使用它才是单页面应用,浏览器不会请求页面;而使用a标签,会重新请求页面。

    <Link to='/path' />
    <Link to={
       pathname, // 路径,即 to 的字符串用法
       search,  // search
       hash,  // hash
       state,  // state 对象
       action,  // location 类型,在点击 Link 时为 PUSH,浏览器前进后退时为 POP,调用 
       replaceState 方法时为 REPLACE
       key,  // 用于操作 sessionStorage 存取 state 对象
    } />
    <Link to='/path' replace={true} /> // 覆盖当前路径

    NavLink

    Link的加强版

    • activeClassName(string):设置选中样式,默认样式名为active
    • activeStyle(object):当元素被选中时,为此元素添加样式
    • exact(bool):为true时,只有当导致和完全匹配class和style才会应用
    • strict(bool):为true时,在确定为位置是否与当前URL匹配时,将考虑位置pathname后的斜线
    • isActive(func):判断链接是否激活的额外逻辑的功能。可以做导航守卫

    Route

    具体的路由规则

    属性:

    // 渲染目标
    component // 渲染组件
    render  
    children
    
    // 地址匹配
    path
    <Route path="/hello/:name"> 
    name为参数名,可以在其渲染组件中获取 this.props.params.name
    <Route path="/files/*.*">
    匹配 /files/hello.jpg  、   /files/hello.html
    <Route path="/files/*">
    匹配 /files/  、 /files/a   、 /files/a/b
    
    exact  // 完全匹配的意思,排他

    Switch

    有<Switch>嵌套,则其中的<Route>在路径相同的情况下,只匹配第一个,这个可以避免重复匹配。

    无<Switch>嵌套,则其中的<Route>在路径相同的情况下全都会匹配,包括上级路径。

    Rediret

    重定向到新地址

    <Redirect to='/path' />

    Prompt

    当用户准备离开该页面时,弹出提示

    message: 字符串/函数,离开页面时的提示信息
    when:布尔值,通过设定条件决定是否启用该组件

    例如:

    <Prompt message="您确定要离开该页面吗?" when={this.state.isOpen} />
    <Prompt
       message = {() => {this.state.isOpen? false: "您确定要离开该页面吗?"}}
    />

    对象和方法 

    被Route绑定的渲染组件,总是被传入三个属性(对象):history、location、match。在渲染组件中也会有很多其他组件,这些组件内部如果想要获取三个对象,需要withRouter(通过装饰器或函数调用的形式都可)。

    我们可以用这三个对象完成很多事情。

    history

    history实现对会话历史的管理。

    length: number   浏览历史堆栈中的条目数
    action: string   路由跳转到当前页面执行的动作,分为 PUSH, REPLACE, POP
    location: object   当前访问地址信息组成的对象,具有如下属性:
    pathname: string   URL路径
    search: string   URL中的查询字符串
    hash: string   URL的 hash 片段
    state: string   例如执行 push(path, state) 操作时,location 的 state 将被提供到堆栈信息里,state 只有在 browser 和 memory history 有效。
    push(path, [state])   在历史堆栈信息里加入一个新条目。
    replace(path, [state])   在历史堆栈信息里替换掉当前的条目
    go(n)   将 history 堆栈中的指针向前移动 n。
    goBack()   等同于 go(-1)
    goForward   等同于 go(1)
    block(prompt)   阻止跳转

    location

    loaction指当前的位置

    {
      hash: '#sdfas',
      key: 'sdfad1'
      pathname: '/about',
      search: '?name=minooo'
      state: {
        price: 123
      }
    }

    可以在不同场景中使用:

    <Link to={location} />
    <NaviveLink to={location} />
    <Redirect to={location />
    history.push(location)
    history.replace(location)

    match

    match对象包含了<Route>如何与URL匹配的信息。

    params: object 路径参数,通过解析 URL 中的动态部分获得键值对
    isExact: bool 为 true 时,整个 URL 都需要匹配
    path: string 用来匹配的路径模式,用于创建嵌套的 <Route>
    url: string URL 匹配的部分,用于嵌套的 <Link>

    路由之间的传值

    大致有三种方法:

    params

    //路由设置
    <Route path=' /user/:id '   component={User} />
    // 传值
    <Link to='/user/2' />
    this.props.history.push("/user/2");
    // 获取值
    this.props.match.params.id

    URL参数

    //路由设置
    <Route path=' /user '   component={User} />
    // 传值
    <Link to='/user?id=2' />
    this.props.history.push("/user?id=2");
    // 获取值
    this.props.location.seacrh // 获得"?id=2",将其进行拆解即可获得

    location对象(哈希路由无法利用)

    又有两种方式:

    (1)loaction.state。传的参数是加密的

    // 路由设置
    <Route path=' /user '   component={User}></Route>
    // 传值
    <Link to={{ pathname:' /user',state:{id:123},search:'?sort=name',hash:'#the-hash'}}> 
    this.props.history.push({pathname:' /user',state:{id:123},search:'?sort=name',hash:'#the-hash'});
    // 获取值
    this.props.location.state.id

    (2)自定义属性

    // 路由设置
    <Route path=' /user '   component={User}></Route>
    // 传值
    <Link to={{ pathname:' /user',abc:{id:123},search:'?sort=name',hash:'#the-hash'}}> 
    this.props.history.push({pathname:' /user',abc:{id:123},search:'?sort=name',hash:'#the-hash'});
    // 获取值
    this.props.location.abc.id

    导航守卫的实现

    在react-router中,并没有提供导航守卫相关的API,作者这样描述:你可以在渲染功能中实现此功能,JSX不需要API,因为它更灵活。

    首先,导航守卫在业务层面可能有三种表现:

    1. 根据状态(如登录/未登录)和身份(等级)将路由进行限制。低等级的用户根本没有定义某些路由。
    2. 路由在任何时候都是完整的,只是根据状态和身份,将入口进行限制(某些Link组件不显示)。没有任何操作能够导向没有权限访问的路由地址。
    3. 不对入口进行限制,根据状态和身份,将某些特定的路由添加拦截。

    在这几种表现中,2和3并不相互冲突。现在有两种思路实现导航守卫:

    • 写一个路由配置表,写一个高阶组件,导航守卫的功能由高阶组件完成,所有与路由绑定的组件都被高阶组件修饰。(对应业务场景3)
    • 写一个路由配置表,定义一个组件:根据路由配置生成最终的<Route>。对于用户没有权限的路由,可以控制不将其渲染。(对应业务场景1)
    • 写一个路由配置表,写一个高阶组件,将是否渲染入口的逻辑写在高阶组件中,所有可能被隐藏的入口都被此高阶组件修饰。(对应业务场景2)

    示例1(业务场景1):

    // 路由配置
    const routerConfig = [
        {
            path:'/',
            component:HomePage,
            auth:false, 
        },{
            path:'/home',
            component:HomePage,
            auth:true, // 表示必须登录才能访问
        },{
            path:'/login',
            component:LoginPage,
        },{
            path:'/404',
            component:ErrorPage
        }
    ];
    
    class RouterTab extends React.Component{
        render(){
            return(
                <HashRouter>
                    <Switch>
                        <RouteGenerator config={routerConfig} />
                    </Switch>
                </HashRouter>
            );
        }
    }
    
    class RouterGenerator extends React.Coponent{
       // 在这里定义限制路由的逻辑(业务场景1)
       render(){
          const routeConf = this.props.config;
          routeConf.map((conf)=>{
             if(conf.auth) // 判断该路由是否满足渲染条件
             {
                if(login) // 判断当前有没有登录
                {
                   retrun <Route path={conf.path} component={conf.component} exact={conf.exact?true:false} />
                }
             }else
             {
                retrun <Route path={conf.path} component={conf.component} exact={conf.exact?true:false} />
             }
          });
       }
    }

    示例2(业务场景3):

    // 将此高阶组件修饰所有需要被守卫的路由组件
    const routerGuard = (RouteConfig) => {
       retrun (WrappedComponent) => {
          rentrun class NewComponent extends React.Component {
    
             componentWillMount(){
                const path = this.props.location.pathname;
                const config = RouteConfig.find(f => f.path === path);
                if(!config)
                {
                   this.props.history.push("/404");
                }
                if(config.auth && !login)
                {
                   this.props.history.push("/login");
                }
             }
    
             render(){
                retrun(
                   <WrappedComponent {...this.props} />
                )
             }
          }
       }
    }

    路由的异步加载 

    如果项目特别大,打包后的js文件会特别大。在首次加载时,一次性地将整个js文件发送给浏览器,一次性地加载所有代码,会对浏览器产生比较大的压力,影响用户体验。我们希望的是,只加载当前访问页面相关的js代码,当路由跳转的时候,再请求相应页面的js代码。这需要使用第三方库,做的比较优秀的有 react-loadable 和 react-async-component。

    react-loadable的原理是将代码进行分割,分割成若干个chunk.js,需要用到的时候就请求过来。

    react-async-component为按需异步加载,使用Promise和高阶组件实现,提高性能。

  • 相关阅读:
    php集成开发环境搭建三种方式
    阿里云服务器ftp连接后21端口无法使用的问题
    Linux CentOS7 安装FTP服务器
    WIN10分盘
    转载:常见的正则表达式
    转载:什么是分布式系统中的幂等性
    会员通过消费攒积分,升级RENEW以及降级的需求
    CASSANDRA How to import and export data
    tmp for cassandra batch delete
    SQL Insert Case When Update
  • 原文地址:https://www.cnblogs.com/V587Chinese/p/11507836.html
Copyright © 2020-2023  润新知