手挽手带你学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 相关文章推荐
javascript:void(0)的真正含义实例分析
Aug 20 Javascript
location.search在客户端获取Url参数的方法
Jun 08 Javascript
40款非常有用的 jQuery 插件推荐(系列一)
Dec 21 Javascript
利用百度地图JSAPI生成h7n9禽流感分布图实现代码
Apr 15 Javascript
jQuery实现统计输入文字个数的方法
Mar 11 Javascript
JQuery标签页效果实例详解
Dec 24 Javascript
JavaScript数组的一些奇葩行为
Jan 25 Javascript
浅谈jQuery效果函数
Sep 16 Javascript
js实现手机发送验证码功能
Mar 13 Javascript
一步步教会你微信小程序的登录鉴权
Apr 09 Javascript
使用异步组件优化Vue应用程序的性能
Apr 28 Javascript
详解微信小程序动画Animation执行过程
Sep 23 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
php+mysql事务rollback&amp;commit示例
2010/02/08 PHP
一个完整的PHP类包含的七种语法说明
2015/06/04 PHP
PHP AjaxForm提交图片上传并显示图片源码
2016/11/29 PHP
PHP中常用的魔术方法
2017/04/28 PHP
PHP编程计算两个时间段是否有交集的实现方法(不算边界重叠)
2017/05/30 PHP
javascript 放大镜效果js组件 qsoft.PopBigImage.v0.35 加入了chrome支持
2009/04/07 Javascript
jQuery创建自己的插件(自定义插件)的方法
2010/06/10 Javascript
读jQuery之十二 删除事件核心方法
2011/07/31 Javascript
jQuery滚动加载图片效果的实现
2013/03/06 Javascript
jQuery瀑布流插件Wookmark使用实例
2014/04/02 Javascript
Struts2+jquery.form.js实现图片与文件上传的方法
2016/05/05 Javascript
js提示框替代系统alert,自动关闭alert对话框的实现方法
2016/11/07 Javascript
Javascript 闭包详解及实例代码
2016/11/30 Javascript
基于JavaScript实现无限加载瀑布流
2017/07/21 Javascript
通俗解释JavaScript正则表达式快速记忆
2017/08/23 Javascript
Vue数据双向绑定原理及简单实现方法
2018/05/18 Javascript
JavaScript对象的浅拷贝与深拷贝实例分析
2018/07/25 Javascript
JavaScript常见JSON操作实例分析
2018/08/08 Javascript
详解element-ui中el-select的默认选择项问题
2019/08/02 Javascript
windows实现npm和cnpm安装步骤
2019/10/24 Javascript
[14:20]刀塔大凶女神互压各路奇葩屌丝
2014/05/16 DOTA
[08:56]DOTA2-DPC中国联赛2月23日Recap集锦
2021/03/11 DOTA
Python BeautifulSoup中文乱码问题的2种解决方法
2014/04/22 Python
实例讲解Python编程中@property装饰器的用法
2016/06/20 Python
Python MySQL数据库连接池组件pymysqlpool详解
2017/07/07 Python
Python使用pandas和xlsxwriter读写xlsx文件的方法示例
2019/04/09 Python
通过 Python 和 OpenCV 实现目标数量监控
2020/01/05 Python
python不使用for计算两组、多个矩形两两间的iou方式
2020/01/18 Python
python根据用户需求输入想爬取的内容及页数爬取图片方法详解
2020/08/03 Python
英国第一的滑雪服装和装备零售商:Snow+Rock
2020/02/01 全球购物
材料物理专业大学毕业生求职信
2013/10/15 职场文书
工商管理专业大学生职业生涯规划范文
2014/03/09 职场文书
就业推荐表自我鉴定范文
2014/03/21 职场文书
个人四风问题对照检查材料
2014/09/26 职场文书
四十年同学聚会致辞
2015/07/28 职场文书
MySQL8.0.18配置多主一从
2021/06/21 MySQL