手挽手带你学React之React-router4.x的使用


Posted in Javascript onFebruary 14, 2019

手挽手带你学React入门三档,带你学会使用Reacr-router4.x,开始创建属于你的React项目

什么是React-router

React Router 是一个基于 React 之上的强大路由库,它可以让你向应用中快速地添加视图和数据流,同时保持页面与 URL 间的同步。通俗一点就是,它帮助我们的程序在不同的url展示不同的内容。

为什么要用React-router

我们开发的时候,不可能所有的东西都展示在一张页面上,在业务场景的要求下,我们要根据不同的URL或者不同的哈希来展示不同的组件,这个我们可以称它为路由。在我们不使用React-router的时候,我们如何去做路由呢?

我在这里给大家举个例子,不使用React-router,来实现一个简单路由。

// App.js
import React,{Component} from 'react'
export default class App extends Component {
  constructor(){
    super()
  // 我们在App.js内部来渲染不同的组件 我们这里采用哈希路由的方式,鉴于React的渲染机制,我们需要把值绑定进入state内部。
    this.state={
      route:window.location.hash.substr(1)
    }
  }
  componentDidMount() {
    // 这里我们通过监听的方式来监听哈希的变化,并且来更新state促进视图更新
    window.addEventListener('hashchange', () => {
      console.log(window.location.hash.substr(1))
     this.setState({
      route: window.location.hash.substr(1)
     })
    })
   }
  render() {
    //在这里我们定义一个RouterView 所有的变化后的组件都会丢到这个RouterView中
    let RouterView = App
    switch (this.state.route) {
      case '/children1':
      RouterView = Children
        break;
      case '/children2':
      RouterView = ChildrenTwo
        break;
      default:
      RouterView = Home
        break;
    }
    return (
      <div>  
        <h1>App</h1>
        <ul>
          <li><a href="#/children1" rel="external nofollow" >children1</a></li> 
          {/* 点击更改哈希值 这里触发我们的监听 然后修改state来触发组件的重新传染 */}
          <li><a href="#/children2" rel="external nofollow" >children2</a></li>
        </ul>
        <RouterView/>
      </div>
    )
  }
}

// 为了展示效果定义子组件一

class Children extends Component{
  constructor(){
    super()
    this.state={
      
    }
  }
  render(){
    return(
      <div>
        <h1>我是子组件1</h1>
        
      </div>
    )
  }
}

// 为了展示效果定义子组件二

class ChildrenTwo extends Component{
  constructor(){
    super()
    this.state={
    
    }
  }
  render(){
    return(
      <div>
        <h1>我是子组件2</h1>
      </div>
    )
  }
}
// 为了展示效果定义Home组件
class Home extends Component{
  constructor(){
    super()
  }
  render(){
    return(
      <h1>我是Home</h1>
    )
  }
}

这样我们通过监听哈希变化的方式实现了我们的第一个简单路由,是不是对于路由的原理有了那么一丢丢的认识呢?接下来我们想象一个场景,这么一个路由出现了/children1/user/about/1,看到这里是不是觉得,用switch case已经蒙B了?我们接下来就要使用到React-router了,这个东西可不需要我们自己去写一大串的switch case了,并且性能啊,整洁度啊等等等方面都比我们自己写的好多了!

React-router 初体验

首先我们在React项目文件目录下执行

npm install react-router-dom --save
npm install react-router --save

要想体验一个新的东西,当然是要拿自己开刀 我们改进上面我们写过的组件

// App.js
import React,{Component} from 'react'
// 首先我们需要导入一些组件...
import { HashRouter as Router, Route, Link } from "react-router-dom";
// 这里有BrowserRouter 和 HashRouter 两种模式 我比较推荐HashRouter来学习 BrowserRouter需要后端配合 单独前端设置 刷新会出现404
// 然后我们把App组件整理干净,大概成这个样子
export default class App extends Component {
  constructor(){
    super()
    this.state={
     
    }
  }
  render() {
    return (
      <Router>
        <div>
        <h1>App</h1>
        <ul>
          <li> <Link to="/">Home</Link></li> 
          <li><Link to="/children1/">children1</Link></li>
          <li><Link to="/children2/">children2</Link></li>
        </ul>
        <Route exact path="/" component={Home} />
        <Route path="/children1" component={Children} />
        <Route path="/children2" component={ChildrenTwo} />
        </div>
      </Router>
    )
  }
}

// 为了展示效果定义子组件一
class Children extends Component{
  constructor(){
    super()
    this.state={
      
    }
  }
  render(){
    return(
      <div>
        <h1>我是子组件1</h1>
      </div>
    )
  }
}
// 为了展示效果定义子组件二
class ChildrenTwo extends Component{
  constructor(){
    super()
    this.state={
    
    }
  }
  render(){
    return(
      <div>
        <h1>我是子组件2</h1>
      </div>
    )
  }
}
// 为了展示效果定义Home组件
class Home extends Component{
  constructor(){
    super()
  }
  render(){
    return(
      <h1>我是Home</h1>
    )
  }
}

这里我们就完成了React-router4.X的初步体验,怎么样~我给大家的第一次的感觉还可以吧~

基本组件

Routers

在React-router4.0中,Routers有两个表现方式 <BrowserRouter> <HashRouter> 这两个标签都将会给你创建一个专门的history对象,BrowserRouter的表现模式需要搭配一个可以响应请求的服务器。HashRouter是静态文件服务器,我们本地开发的时候,建议使用HashRouter。这里需要注意一下,BrowserRouter和 HashRouter标签下面,只允许存在一个标签 具体写法如下

<BrowserRouter>
  <div>
    {/*其余内容写在这里面*/}
  </div>
</BrowserRouter>

<HashRouter>
  <div>
    {/*其余内容写在这里面*/}
  </div>
</HashRouter>

Route

注意,最外层的是Router 这里是 Route 这是我们的路由匹配组件,它有两个 Route和Switch

Route 组件拥有多个属性,这在我们后期的路由传参中将会用到。这里我们需要简单了解几个属性 path component exact strict

path 是我们匹配的地址,当地址匹配的时候 我们才会去渲染 component内的组件内容

path 后面如果书写模式带了 /: 这样的内容,那么这里将会成为占位符 我们可以利用占位符来取到对应路径的参数 使用 this.props.match.params+占位符的名字 即可拿到

exact 属性来规定我们是否严格匹配

strict 则是严格匹配模式 我们规定的路径使用/one/来书写 如果没有完全匹配 /one/ 则不会展示

<Route exact path="/one" component={App} />
// 这里我们加了exact 那么 路径完全等于/one的时候才会渲染App /one/ one /one/two 后面这三种情况均不会渲染App

// 相反 如果我们没有加 exact 的时候 /one /one/two App都会被渲染

<Route strict path="/one/" component={App} />
// 我们加了 strict 以后 /one 将不会渲染App 而如果没有 strict 这种情况下 /one 是可以渲染App的

同时React-router给我们提供了一个Switch标签 在这个标签内 我们只会渲染一个Route 并且使第一个符合条件的Route 这是什么意思呢?我们来看代码

<Route path="/about" component={About} />
<Route path="/:User" component={User} />
<Route path="/" component={Home} />
<Route component={NoMatch} />

在这样的路由下 我们匹配/about 会发现 所有的路由都可以匹配到并且渲染了出来,这肯定不是我们想要的结果 于是我们给它嵌套一个 Switch

<Switch>
  <Route path="/about" component={About} />
  <Route path="/:User" component={User} />
  <Route path="/" component={Home} />
  <Route component={NoMatch} />
</Switch>

这时候我们就只会匹配到第一个/about,仅仅渲染About,大家根据实际需求去决定是否嵌套Switch使用

Link和NavLink

Link 主要api是to,to可以接受string或者一个object,来控制url。我们代码里看看书写方法

<Link to='/one/' /> 
  // 这就是路由到one 搭配Router使用 当然我们可以使用一个对象

  <Link to={{
    pathname:'/one',
    search:'?name=qm',
    hash:'#two',
    state:{
      myName:'qimiao'
    }
  }} />
  // 这样我们点击link不仅可以到one 还可以传递一些参数

NavLink 它可以为当前选中的路由设置类名、样式以及回调函数等。使用如下

<NavLink exact activeClassName='navLink' to='/one/' /> 
  // 这就是路由到one 搭配Router使用 当然我们可以使用一个对象

  <NavLink exact activeClassName='navLink' to={{
    pathname:'/one',
    search:'?name=qm',
    hash:'#two',
    state:{
      myName:'qimiao'
    }
  }} />
  // 这里的exact 同样是严格比配模式 同Route
  // 这样我们可以为当前选中的路由设置样式了

子路由的书写

在react-router4之前的版本,子路由通过路由嵌套就可以实现了,但是这一个方法到了React-router4中就行不通了

先来一个之前的写法,当然也是错误示例

export default class App extends Component {
  constructor(){
    super()
    this.state={
     
    }
  }
  render() {
    return (
      <Router>
        <div>
        <h1>App</h1>
        <ul>
          <li> <Link to="/home">Home</Link></li> 
          <li><Link to="/children1/">children1</Link></li>
          <li><Link to="/children2/">children2</Link></li>
        </ul>
        <Route path="/home" component={Home} >
          <Route path="children1" component={Children} />
          <Route path="children2" component={ChildrenTwo} />
          {/*在4.0以后的版本这样都会报错 那么我们应该怎么写呢*/}
        </Route>
      
        </div>
      </Router>
    )
  }
}

在react-router4.x版本中 我们子路由必须要在子组件内部了

export default class App extends Component {
  constructor(){
    super()
    this.state={
     
    }
  }
  render() {
    return (
      <Router>
        <div>
        <h1>App</h1>
        <ul>
          <li> <Link to="/home">Home</Link></li> 
          {/* 同样 这两个link让他们转移到Home中 我们的home组件就变成了下面的样子 */}
        </ul>
        <Route path="/home" component={Home} >
         {/*<Route path="children1" component={Children} />*/} 
         {/*<Route path="children2" component={ChildrenTwo} />*/} 
          {/*先把这里注释掉 然后我们来到Home组件内*/}
        </Route>
      
        </div>
      </Router>
    )
  }
}

// home内部用{this.props.match.url+子路由路径}来获取当前的路径并且加上我们要路由到的位置来进行路由匹配和路径跳转匹配 这样书写 Children和ChildrenTwo就是home的子路由了
class Home extends Component{
  constructor(){
    super()
  }
  
  render(){
    return(
      <div>
      <h1>我是Home</h1>
      <li><Link to={`${this.props.match.url}/children1`}>children1</Link></li>
      <li><Link to={`${this.props.match.url}/children2`}>children2</Link></li>
      <Route path={`${this.props.match.url}/children1`} component={Children} />
      <Route path={`${this.props.match.url}/children2`} component={ChildrenTwo} />   
      </div>
    )
  }
}

路由跳转

声明式跳转上面已经说过了 Link和NavLink 两个标签就可以满足了 我们主要说一下js跳转

在4.0刚刚发布的时候 this.props.history.push('路径')这个方法已经行不通了,不过值得庆幸的是,我现在所使用的4.3.1版本又可以使用这个方法来进行js路由跳转了。

我们用home组件来举个例子

class Home extends Component{
  constructor(){
    super()
  }
  toPath=(home)=>{
    console.log(123)
    this.props.history.push({ //我们把要传参的东西都放在push对象内了
      pathname:home,  //我们要到达哪个路由
      search:"?a=1",  //明文传参的模式
      query:{'type':'type'}, //query对象传参
      state:{     //state对象传参
        b:456
      }
    })
  // this.props.history.push('/123')
  }
  render(){
    return(
      <div>
      <h1 onClick={()=>{this.toPath(`${this.props.match.url}/children1/123`)}}>我是Home</h1>
      <li><Link to={`${this.props.match.url}/children1`}>children1</Link></li>
      <li><Link to={`${this.props.match.url}/children2`}>children2</Link></li>
      <Route path={`${this.props.match.url}/children1/:id`} component={Children} />
      <Route path={`${this.props.match.url}/children2`} component={ChildrenTwo} />   
      </div>
    )
  }
}

/*相应的 我们在Children 组件里面有对应的方法来获取参数。*/

class Children extends Component{
  constructor(){
    super()
    this.state={
      
    }
  }
  render(){
    console.log(this.props.match.params.id) //这种是通过路径上面的:id传过来的参数
    console.log(this.props.location.query) //这是通过push的参数对象中的query传过来的 和vue的query有区别 它不在地址栏 刷新丢失
    console.log(this.props.location.state) //这是通过push的参数对象中的state传过来的 它不在地址栏 刷新丢失
    console.log(this.props.location.search) //暴露在地址栏,需要自行处理获取数据


    return(
      <div>
        <h1>我是子组件1 </h1>
      </div>
    )
  }
}

总结

这一期我们主要还是讲了react-router4.x的基础使用和传参方法,react-router4.x坑比较多,不过使用熟练了会让你感觉很爽,大家不要吝啬自己的时间多多学习。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
基于prototype的validation.js发布2.3.4新版本,让你彻底脱离表单验证的烦恼
Dec 06 Javascript
Javascript实现真实字符串剩余字数提示的实例代码
Oct 22 Javascript
JavaScript—window对象使用示例
Dec 09 Javascript
Jquery下EasyUI组件中的DataGrid结果集清空方法
Jan 06 Javascript
js实现Select列表各项上移和下移的方法
Aug 14 Javascript
jQuery实现带滑动条的菜单效果代码
Aug 26 Javascript
javascript中Date对象的使用总结
Nov 21 Javascript
微信小程序滚动Tab实现左右可滑动切换
Aug 17 Javascript
微信小程序提取公用函数到util.js及使用方法示例
Jan 10 Javascript
jQuery实现ajax的嵌套请求案例分析
Feb 16 jQuery
微信小程序如何实现精确的日期时间选择器
Jan 21 Javascript
JavaScript常用工具函数大全
May 06 Javascript
详解JavaScript原生封装ajax请求和Jquery中的ajax请求
Feb 14 #jQuery
vue中各种通信传值方式总结
Feb 14 #Javascript
微信小程序实现banner图轮播效果
Jun 28 #Javascript
如何使用VuePress搭建一个类型element ui文档
Feb 14 #Javascript
JavaScript类型相关的常用操作总结
Feb 14 #Javascript
VuePress 快速踩坑小结
Feb 14 #Javascript
使用vuepress搭建静态博客的示例代码
Feb 14 #Javascript
You might like
xml在joomla表单中的应用详解分享
2012/07/19 PHP
PHP使用DOM对XML解析处理操作示例
2019/07/04 PHP
js计算两个时间之间天数差的实例代码
2013/11/19 Javascript
js事件监听器用法实例详解
2015/06/01 Javascript
百度地图api如何使用
2015/08/03 Javascript
jquery精度计算代码 jquery指定精确小数位
2017/02/06 Javascript
vue-cli中的webpack配置详解
2017/09/25 Javascript
JS实现字符串中去除指定子字符串方法分析
2018/05/17 Javascript
Vue中在新窗口打开页面及Vue-router的使用
2018/06/13 Javascript
浅谈微信小程序flex布局基础
2018/09/10 Javascript
jquery.param()实现数组或对象的序列化方法
2018/10/08 jQuery
js中获取URL参数的共用方法getRequest()方法实例详解
2018/10/24 Javascript
详解基于Wepy开发小程序插件(推荐)
2019/08/01 Javascript
微信小程序实现树莓派(raspberry pi)小车控制
2020/02/12 Javascript
jquery实现手风琴案例
2020/05/04 jQuery
vue结合el-upload实现腾讯云视频上传功能
2020/07/01 Javascript
MAC中PyCharm设置python3解释器
2017/12/15 Python
Python KMeans聚类问题分析
2018/02/23 Python
Python实现手写一个类似django的web框架示例
2018/07/20 Python
分享Python切分字符串的一个不错方法
2018/12/14 Python
python中sort sorted reverse reversed函数的区别说明
2020/05/11 Python
Python+OpenCV图像处理——实现直线检测
2020/10/23 Python
Born鞋子官网:Born Shoes
2017/04/06 全球购物
Woolworth官网:澳洲第一大超市
2017/06/25 全球购物
Aeropostale官网:美国著名校园品牌及青少年服饰品牌
2019/03/21 全球购物
体育专业个人的求职信范文
2013/09/21 职场文书
老教师工作总结的自我评价
2013/09/27 职场文书
会计专业自荐信范文
2013/12/02 职场文书
家长评语大全
2014/01/22 职场文书
教师节宣传方案
2014/05/23 职场文书
行政工作试用期自我评价
2014/09/14 职场文书
村长党的群众路线教育实践活动个人对照检查材料
2014/09/23 职场文书
老公保证书
2015/01/17 职场文书
春季运动会开幕词
2015/01/28 职场文书
死亡诗社观后感
2015/06/05 职场文书
Java并发编程之原子性-Atomic的使用
2022/03/16 Java/Android