手挽手带你学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脚本实现Web页面信息交互
Dec 21 Javascript
javascript中对对层的控制
Dec 29 Javascript
Extjs Label的 fieldLabel和html属性值对齐的方法
Jun 15 Javascript
Javascript模块化编程详解
Dec 01 Javascript
js弹出框、对话框、提示框、弹窗实现方法总结(推荐)
May 31 Javascript
jQuery鼠标事件总结
Oct 13 Javascript
BootStrap3使用错误记录及解决办法
Dec 22 Javascript
Angular中自定义Debounce Click指令防止重复点击
Jul 26 Javascript
JavaScript实现的仿新浪微博原生态输入字数即时检查功能【兼容IE6】
Sep 26 Javascript
详解jQuery-each()方法
Mar 13 jQuery
JS控制GIF图片的停止与显示
Oct 24 Javascript
详解JS WebSocket断开原因和心跳机制
May 07 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 远程关机实现代码
2009/11/10 PHP
PHP $_FILES函数详解
2011/03/09 PHP
彻底删除thinkphp3.1案例blog标签的方法
2014/12/05 PHP
Laravel框架实现的记录SQL日志功能示例
2018/06/19 PHP
实例讲解php实现多线程
2019/01/27 PHP
JS实现自动切换文字的导航效果代码
2015/08/27 Javascript
Bootstrap和Angularjs配合自制弹框的实例代码
2016/08/24 Javascript
JavaScript如何一次性展示几万条数据
2017/03/30 Javascript
基于nodejs+express4.X实现文件下载的实例代码
2017/07/13 NodeJs
利用JQuery操作iframe父页面、子页面的元素和方法汇总
2017/09/10 jQuery
初探js和简单隐藏效果的实例
2017/11/23 Javascript
vue中实现在外部调用methods的方法(推荐)
2018/02/08 Javascript
NodeJS父进程与子进程资源共享原理与实现方法
2018/03/16 NodeJs
vue+axios新手实践实现登陆的示例代码
2018/06/06 Javascript
3分钟读懂移动端rem使用方法(推荐)
2019/05/06 Javascript
layui复选框的全选与取消实现方法
2019/09/02 Javascript
浅析JS中NEW的实现原理及重写
2020/02/20 Javascript
js编写简易的计算器
2020/07/29 Javascript
浅谈vue生命周期共有几个阶段?分别是什么?
2020/08/07 Javascript
[02:51]DOTA2英雄基础教程 风暴之灵
2013/12/23 DOTA
[04:03]辉夜杯主赛事 12月25日RECAP精彩回顾
2015/12/26 DOTA
Python爬虫DNS解析缓存方法实例分析
2017/06/02 Python
浅谈Pandas 排序之后索引的问题
2018/06/07 Python
pycharm恢复默认设置或者是替换pycharm的解释器实例
2018/10/29 Python
[原创]Python入门教程3. 列表基本操作【定义、运算、常用函数】
2018/10/30 Python
Python 如何实现访问者模式
2020/07/28 Python
Python正则re模块使用步骤及原理解析
2020/08/18 Python
MoviePy常用剪辑类及Python视频剪辑自动化
2020/12/18 Python
领先的钻石和订婚戒指零售商:Diamonds-USA
2016/12/11 全球购物
成教毕业生自我鉴定
2013/10/23 职场文书
大学生职业规划范文:象牙塔生活的四年计划
2014/01/14 职场文书
分家协议书
2014/04/21 职场文书
竞选大队长演讲稿
2014/04/29 职场文书
工作时间擅自离岗检讨书
2014/10/24 职场文书
幼儿园法制宣传日活动总结
2014/11/01 职场文书
爱心助学感谢信
2015/01/21 职场文书