手挽手带你学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 相关文章推荐
基于jQuery的遍历同id元素 并响应事件的代码
Jun 14 Javascript
在JavaScript中对HTML进行反转义详解
May 18 Javascript
Js+Ajax,Get和Post在使用上的区别小结
Jun 08 Javascript
jQuery validate 验证radio实例
Mar 01 Javascript
jQuery插件FusionWidgets实现的AngularGauge图效果示例【附demo源码】
Mar 23 jQuery
JS正则替换去空格的方法
Mar 24 Javascript
详解如何使用PM2将Node.js的集群变得更加容易
Nov 15 Javascript
javascript连接mysql与php通过odbc连接任意数据库的实例
Dec 27 Javascript
webpack引入eslint配置详解
Jan 22 Javascript
mpvue构建小程序的方法(步骤+地址)
May 22 Javascript
Vue组件中prop属性使用说明实例代码详解
May 31 Javascript
详解微信小程序(Taro)手动埋点和自动埋点的实现
Mar 02 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
全国FM电台频率大全 - 25 云南省
2020/03/11 无线电
重料打造自己的“宝马”---第三代
2021/03/02 无线电
PHP substr 截取字符串出现乱码问题解决方法[utf8与gb2312]
2011/12/16 PHP
一个简单的php加密解密函数(动态加密)
2013/06/19 PHP
Thinkphp 中 distinct 的用法解析
2016/12/14 PHP
小议Function.apply()之二------利用Apply的参数数组化来提高 JavaScript程序性能
2006/11/30 Javascript
JavaScript实现点击自动选择TextArea文本的方法
2015/07/02 Javascript
JS实现在状态栏显示打字效果完整实例
2015/11/02 Javascript
js正则表达式replace替换变量方法
2016/05/21 Javascript
BootStrap实现树形目录组件代码详解
2016/06/21 Javascript
Bootstrap中文本框的宽度变窄并且加入一副验证码图片的实现方法
2016/06/23 Javascript
JavaScript中ES6 Babel正确安装过程
2016/07/18 Javascript
vue.js在标签属性中插入变量参数的方法
2018/03/06 Javascript
Vue2.0 事件的广播与接收(观察者模式)
2018/03/14 Javascript
react实现点击选中的li高亮的示例代码
2018/05/24 Javascript
Angular使用ControlValueAccessor创建自定义表单控件
2019/03/08 Javascript
vue 解决兄弟组件、跨组件深层次的通信操作
2020/07/27 Javascript
Vue 组件的挂载与父子组件的传值实例
2020/09/02 Javascript
[02:42]决战东方!DOTA2亚洲邀请赛重启荣耀之争
2017/03/17 DOTA
[58:09]Spirit vs NB Supermajor小组赛 A组败者组决赛 BO3 第三场 6.2
2018/06/03 DOTA
Python中使用OpenCV库来进行简单的气象学遥感影像计算
2016/02/19 Python
python3新特性函数注释Function Annotations用法分析
2016/07/28 Python
Python实现登录接口的示例代码
2017/07/21 Python
机器学习python实战之决策树
2017/11/01 Python
Python输入二维数组方法
2018/04/13 Python
python opencv实现切变换 不裁减图片
2018/07/26 Python
Stuart Weitzman美国官网:美国奢华鞋履品牌
2016/08/18 全球购物
产品工艺师的岗位职责
2013/11/15 职场文书
运动会广播稿80字
2014/01/23 职场文书
学雷锋标语
2014/06/25 职场文书
装修活动策划方案
2014/08/27 职场文书
大学生简历自我评价2015
2015/03/03 职场文书
同事打架检讨书
2015/05/06 职场文书
《百分数的认识》教学反思
2016/02/19 职场文书
Vue-Element-Admin集成自己的接口实现登录跳转
2021/06/23 Vue.js
MySQL新手入门进阶语句汇总
2022/09/23 MySQL