React Router 使用

前言

做为 React 全家桶的一员,若是咱们想要开发一个 React 应用,那么 react-router 基本上是咱们绕不过去的基础。基于此,对它的了解和使用也是必不可少的一步html

本文将重点介绍实际应用中经常使用的一些 API 以及实践过程当中遇到的一些问题,目标很简单:会用前端

基于 react-router v5.0.1WEB 应用程序

安装

国际惯例,首先咱们须要安装vue

npm install --save react-router-dom

从这一步开始,已经有同窗有疑问了:咱们明明在说 react-router 怎么要下载安装 react-router-domreact

React Router 如今已经被划分红了三个包:react-routerreact-router-domreact-router-nativegit

react-routerReact Router 应用提供了核心的路由组件和函数,另外两个包提供了特定环境的组件(浏览器和 react-native 对应的平台),不过他们也是将 react-router 导出的模块再次导出

由于咱们须要开发一个 web 应用,因此直接安装 react-router-dom 就能够了github

初体验

首先,让咱们经过一个小小的示例来感知一下 react-routerweb

import React from 'react'
import ReactDom from 'react-dom'
import { BrowserRouter, Route, Link, Switch } from 'react-router-dom'

const Index = () => <div>Index页面</div>

const About = () => <div>About页面</div>

const App = () => {
    return (
        <BrowserRouter>
            <div>
                <div>
                    <ul>
                        <li><Link to='/'>Index</Link></li>
                        <li><Link to='/about'>About</Link></li>
                    </ul>
                </div>
                <div>
                    <Switch>
                        <Route path='/' exact component={Index}></Route>
                        <Route path='/about' exact component={About}></Route>
                    </Switch>
                </div>
            </div>
        </BrowserRouter>
    )
}

ReactDom.render(<App />, document.getElementById('app'))

经过上面的代码咱们已经实现了路由的基本功能,匹配不一样的路径,渲染不一样的组件。下面,咱们就上面的示例,认识一些 react-router 中高频率出现的概念vue-router

经常使用组件

Router 组件

React Router 应用程序的核心,每一个 router 都会建立一个 history 对象,用来保持对当前位置的追踪npm

web 项目中,react-router-dom 提供了 BrowserRouterHashRouter 路由。这两个路由都会为你建立一个专门的 history 对象。至于使用场景,通常状况下若是咱们使用的是一个非静态的站点、要处理不一样的 url 就使用 BrowserRouter,相反若是只处理静态的 url,则使用 HashRouter编程

Route 组件

Route 组件的主要职责:当连接符合匹配规则时,渲染组件

路由匹配是经过比较 Routepath 属性和当前地址的 pathname 来实现的。当一个 Route 匹配成功时,它将渲染其内容,当它不匹配时就会渲染 null。没有路径的 Route 将始终被匹配

Route 组件经常使用属性:

  • path: 字符串类型,用来匹配 ulr
  • exact: boolean 类型,若是为 true,则只有在路径彻底匹配 location.pathname 时才匹配
  • component: 只有当位置匹配时才会渲染的 React 组件

注意点:

Route 组件属性都不是必须的,若是缺乏 path 属性,那么将会匹配到任意 url
<Route path='/' exact component={Index} />
<Route component={About} />
使用 render 或者 children 属性能够替代 component 属性,因为 renderchildren 都是函数的形式,因此能够在它们当中作一些比较复杂的逻辑

render 函数也是在匹配 url 的时候渲染,而 children 函数 任什么时候候 都渲染,当路由匹配的时候 match 是一个对象,不然为 null

当三者一块儿使用的时候,优先级为 children > component > render

<!-- 使用 render 属性 -->
<Route path='/about' render={() => <div>这个是render渲染的about页面</div>} />

<Route path='/about' render={(props) => <About {...props} />} />

<!-- 使用 children 属性 -->
<Route path='/about' children={() => <div>这是一个children渲染的about页面</div>}

<Route path='/about' children={({match}) => match ? <div>1</div> : <div>2</div> }

Switch 组件

渲染与该地址匹配的第一个子节点 Route 或者 Redirect

这个组件最重要的做用是能够将 Route 组件分组

<Switch>
    <Route path='/user' render={()=><div>user页面</div>} />
    <Route path='/:id' render={()=><div>子成员</div>} />
    <Route render={()=><div>about页面</div>} />
</Switch>

在上面这个示例中,在没有 Switch 组件包裹的状况下,若是 ulr/user,那么三个页面将会所有匹配到。这样的设计在必定程度上给咱们提供了便利,好比说一个公共页面须要渲染好几个组件的状况。可是有时候咱们并不想访问到所有的匹配组件,这个时候就能够将这些 Route 组件使用 Switch 包裹起来,它将永远渲染符合匹配项的第一个组件

注意点:

  • Switch 匹配的规则是同一个组中渲染第一个匹配组件,也就是说若是是包裹在两个不一样的 Switch 组件中的,会分别渲染匹配到的第一个组件
  • Switch 组件中不能嵌套内置标签元素,好比 div span,可是能够嵌套组件,甚至能够添加 path 属性进行匹配, 实际上 Route 自己就是组件,可是建议仍是只嵌套 Route 或者 Redirect 组件

Link 与 NavLink

相信小伙伴们看过前面的示例以后,应该对 Link 不会陌生了。它的做用就是提供声明式的可访问导航

Link 经常使用属性:
  • to:能够是 String 类型或者具备 pathnamesearchhashstate任何属性的对象

    pathname: 表示要连接到的路径的字符串

    search: 表示查询参数的字符串形式

    hash: 放入网址的 hash

    state: 状态持续到 location

  • replaceboolean 类型,若是为 true,点击连接将替换当前历史记录
NavLink 一个特殊版本的 Link,当它与当前 URL 匹配时,为其渲染元素添加样式属性,其用法与 Link 基本相同

注意点:

  • 给渲染元素添加属性可使用 activeClassName 或者 activeStyle 属性进行添加,简单来讲就是使用 class 类或者行内样式
  • NavLink 有一个 exact 属性,若是为 true,则仅在位置彻底匹配时才应用 active 的类/样式

Redirect 组件

顾名思义,重定向组件,组件中的 to 属性是必须的

属性:

  • tostring 类型或者一个对象(pathname 属性是重定向到的 URL
  • pushboolean 类型,当 true 时,重定向会将新地址推入 history 中,而不是替换当前地址,就是经过 history.push 或者 history.replace 实现
  • from:重定向 from 的路径名,简单说就是将要进入的 url
  • exact:彻底匹配 from;至关于 Route.exact

这个组件在一些场景中有很好的效果,好比咱们登陆场景,前面咱们介绍过的 Route 组件渲染属性使用 render 或者 children 的时候,就彻底能够根据判断条件执行不一样的路由跳转

<!-- 官网示例代码 -->
<Route exact path='/' render={()=>(
    loggedIn ? (
    <Redirect to="/dashboard"/>
  ) : (
    <PublicHomePage/>
  )
)} />

<!--或者-->
<Route path='/about' children={({match})=>(
    match ? (
        <About />
    ) : (
        <User />
    )
)} />

前面介绍 Switch 组件时,有过它的身影,实际上它能够和 Switch 组件很好的配合,好比:

<Switch>
    <Redirect from='/user' to='/about' />
    <Route path='/user' render={()=><div>User页面</div>} />
</Switch>

须要注意的地方:

  • from 属性只能用于在 Redirect 内部渲染 Switch 时匹配地址
  • Redirect 组件中 from 匹配的 Route 要在前面定义
<!--错误姿式,这样是没有效果的-->
<Route path='/user' render={()=><div>User页面</div>} />
<Redirect from='/user' to='/about' />

withRouter

默认状况下,通过路由匹配的组件才拥有路由参数,咱们就能够在其中使用 编程式导航,好比:

this.props.history.push('/about')

然而,不是全部的组件都是与路由相连的,好比直接在浏览器输入地址打开的。这个时候咱们访问组件 props 的时候,它是一个空对象,就没办法访问 props 中的 historymatchlocation 等对象

因此 这个时候 withRouter 闪亮登场

withRouter 的用法很简单:

import React, { Component } from 'react';
<!--引入-->
import { Route, Link, Switch, withRouter } from 'react-router-dom' 

class App extends Component {
    render() { 
    <!-- 没有使用 withRouter 的时候,是一个空对象-->
        console.log(this.props)
        return ( 
            <div>
                <Link to='/'>Index</Link>
                <Link to='/about'>About</Link>
                <Switch>
                    <Route path='/' exact render={()=> <div>Index页面</div>} />
                    <Route path='/about' render={()=> <div>About页面</div>} />
                </Switch>
            </div>
         );
    }
}
 
<!--执行-->
export default withRouter(App)

固然,还有不少种使用方式,好比经过 withRouter 监听 loaction 对象改变文档标题或者配合 redux 使用等等

详见 示例demo

进一步

了解了 react-router 的这些基本知识点,貌似咱们已经能够写出来一个用路由搭建的项目了。可是,请暂时停下脚步想一下:在一个项目当中,若是咱们遇到嵌套的路由呢、动态参数的路由呢?固然,只用前面了解到的东西,彻底能够写出来,但那是在是太 low

match 对象

在解答前面的两个问题以前,咱们须要先了解一个 match 对象

相信在前面的 withRouter 模块,小伙伴们已经知道了 match 对象的存在,在动态路由和路由嵌套时,咱们会常常和它打交道

一个 match 对象中包涵了有关如何匹配 URL 的信息

它包含如下属性:

  • params:与动态路径的 URL 对应解析,它里面包含了动态路由里面的信息
  • path:用于匹配的路径模式
  • url:用于匹配部分的 URL
  • isExact - 若是为 true 匹配整个 URL (没有结尾字符)

注意点:

  • 若是 Route 没有 path,那么将会一直与他最近的父级匹配。这也一样适用于 withRouter
  • match 对象中的 urlpath ,简单来讲 path 是匹配的规则, url 则是实际匹配到的路径

动态路由

了解了 match 对象,动态路由的定义其实很简单

<Link to='/video/1'>视频教程1</Link>
<Link to='/video/2'>视频教程2</Link>

<Route path='/video/:id' component={Video} />

Route 组件能够匹配到 Link 连接跳转的路径,而后再 match 对象的 params 属性中就能够拿到动态数据的具体信息

嵌套路由

React Router 4 再也不提倡中心化路由,取之的是路由存在于布局和 UI 之间,Route 自己就是一个组件

实现路由嵌套最简单的方式:

<!--父组件-->
<Route path='/workplace' component={Workplace} />

<!--子组件-->
<Route path='/workplace/money' component={Money} />

固然,使用 match 来进行匹配会更加优雅

<!--父组件-->
<Route path='/video' component={Video} />

<!--子组件-->
<Route path={`${this.props.match.url}/react`} component={ReactVideo} />

注意点:

  • 使用嵌套路由父级不能使用 exact

使用这样的方式来配置路由规则,咱们就只须要考虑 component 的渲染时机就能够了。可是,一样的也会给咱们带来一些问题,好比说路由规则不是很直观,尤为是对于写过 vue 的小伙伴来讲,要是有一个像配置 vue-router 规则的东西就行了。这个时候,咱们能够试着去了解一个这个东西了 react-router-config

详见 示例demo

后记

突如其来的结束语

关于 react-router 的基本用法就是想上面介绍的那样,可是想要探究更多有意思或者更优雅的用法,还须要咱们在具体的项目中去磨练,好比说路由的拆分、按需加载等等一系列东西

若是你也对 React 中的其余内容感兴趣,想要了解更多前端片断,能够 点击这里 ,欢迎 star 关注

参考

官方文档

简明React Router v4教程

相关文章
相关标签/搜索