手挽手带你学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中instanceof与typeof运算符的用法及区别详细解析
Nov 19 Javascript
javascript运行机制之this详细介绍
Feb 07 Javascript
jQuery拖拽div实现思路
Feb 19 Javascript
JS获取checkbox的个数简单实例
Aug 19 Javascript
JS实现页面载入时随机显示图片效果
Sep 07 Javascript
jQuery插件zTree实现更新根节点中第i个节点名称的方法示例
Mar 08 Javascript
node.js 抓取代理ip实例代码
Apr 30 Javascript
前端构建工具之gulp的配置与搭建详解
Jun 12 Javascript
利用vue开发一个所谓的数独方法实例
Dec 21 Javascript
细说webpack6 Babel的使用详解
Sep 26 Javascript
js常用方法、检查是否有特殊字符串、倒序截取字符串操作完整示例
Jan 26 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实现图片上传、剪切功能
2016/05/07 PHP
关于php几种字符串连接的效率比较(详解)
2017/02/22 PHP
PHP Post获取不到非表单数据的问题解决办法
2018/02/27 PHP
解决PHP curl或file_get_contents下载图片损坏或无法打开的问题
2019/10/11 PHP
利用onresize使得div可以随着屏幕大小而自适应的代码
2010/01/15 Javascript
11个用于提高排版水平的基于jquery的文字效果插件
2012/09/14 Javascript
运用jQuery定时器的原理实现banner图片切换
2014/10/22 Javascript
JS实现单行文字不间断向上滚动的方法
2015/01/29 Javascript
JavaScript如何动态创建table表格
2020/08/02 Javascript
Bootstrap框架动态生成Web页面文章内目录的方法
2016/05/12 Javascript
Bootstrap教程JS插件滚动监听学习笔记分享
2016/05/18 Javascript
IntersectionObserver API 详解篇
2016/12/11 Javascript
浅析 NodeJs 的几种文件路径
2017/06/07 NodeJs
使用Require.js封装原生js轮播图的实现代码
2017/06/15 Javascript
mpvue 项目初始化及实现授权登录的实现方法
2020/07/20 Javascript
ES2020系列之空值合并运算符 '??'
2020/07/22 Javascript
解决vant框架做H5时踩过的坑(下拉刷新、上拉加载等)
2020/11/11 Javascript
[03:47]2015国际邀请赛第三日现场精彩回顾
2015/08/08 DOTA
基于python实现微信模板消息
2015/12/21 Python
python 开发的三种运行模式详细介绍
2017/01/18 Python
python实现公司年会抽奖程序
2019/01/22 Python
python自动发送测试报告邮件功能的实现
2019/01/22 Python
如何通过Django使用本地css/js文件
2020/01/20 Python
python 实现图片修复(可用于去水印)
2020/11/19 Python
css3的transition效果和transfor效果示例介绍
2013/10/30 HTML / CSS
波兰家具和室内装饰品购物网站:Vivre
2018/04/10 全球购物
会计实习生自我鉴定
2013/12/12 职场文书
股份转让协议书
2014/04/12 职场文书
公司股份转让协议书范本
2015/01/28 职场文书
小兵张嘎观后感300字
2015/06/03 职场文书
看雷锋电影观后感
2015/06/10 职场文书
《7的乘法口诀》教学反思
2016/02/18 职场文书
教学反思怎么写
2016/02/24 职场文书
Sql Server 行数据的某列值想作为字段列显示的方法
2022/04/20 SQL Server
Java处理延时任务的常用几种解决方案
2022/06/01 Java/Android
详解Spring Security如何在权限中使用通配符
2022/06/28 Java/Android