手挽手带你学React:三档 React-router4.x的使用

2019-02-13 admin

手挽手带你学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">children1</a></li>  
                    {/* 点击更改哈希值 这里触发我们的监听 然后修改state来触发组件的重新传染 */}
                    <li><a href="#/children2">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坑比较多,不过使用熟练了会让你感觉很爽,大家不要吝啬自己的时间多多学习,博客开通了注册投稿功能,如果大家有好的学习文章,经典总结,可以投稿,可以扫码加我微信申请专栏~感谢大家的阅读和观看。

视频制作中

[转载]原文链接:https://segmentfault.com/a/1190000018139632

本站文章除注明转载外,均为本站原创或编译。欢迎任何形式的转载,但请务必注明出处。

转载请注明:文章转载自 JavaScript中文网 [https://www.javascriptcn.com]

本文地址:https://www.javascriptcn.com/read-53689.html

文章标题:手挽手带你学React:三档 React-router4.x的使用

相关文章
bootstrap PrintThis打印插件使用详解
bootstrap PrintThis打印效果图: 如图,这个是调用了谷歌的打印,使用很方便,可以自己調样式,需要的可以研究一下,这边贴出使用方法。 附上GitHub:https://github.com/jasonday/printTh...
2017-03-16
css布局的各种FC简单介绍:BFC,IFC,GFC,FFC
什么是FC? Formatting Context,格式化上下文,指页面中一个渲染区域,拥有一套渲染规则,它决定了其子元素如何定位,以及与其他元素的相互关系和作用。 BFC 什么是BFC Block Formatting Context,块...
2018-05-17
一些前端学习中好的书籍,整理
一、Javascript方面的书籍: 1 JavaScript权威指南(第6版):号称javascript圣经,前端必备;前端程序员学习核心JavaScript语言和由Web浏览器定义的JavaScript API的指南和综合参考手册; 2...
2015-11-12
vue 数组遍历方法forEach和map的原理解析和实际应用
一、前言 forEach和map是数组的两个方法,作用都是遍历数组。在vue项目的处理数据中经常会用到,这里介绍一下两者的区别和具体用法示例。 二、代码 1. 相同点 都是数组的方法 都用来遍历数组 两个函数都有4个参数:匿名函数中可传3...
2018-11-15
js性能优化 如何更快速加载你的JavaScript页面
确保代码尽量简洁 不要什么都依赖JavaScript。不要编写重复性的脚本。要把JavaScript当作糖果工具,只是起到美化作用。别给你的网站添加大量的JavaScript代码。只有必要的时候用一下。只有确实能改善用户体验的时候用一下。 ...
2015-11-12
10个强大的纯CSS3动画案例分享
我们的网页外观主要由CSS控制,编写CSS代码可以任意改变我们的网页布局以及网页内容的样式。CSS3的出现,更是可以让网页增添了不少动画元素,让我们的网页变得更加生动有趣,并且更易于交互。本文分享了10个非常炫酷的CSS3动画案例,希望大家...
2015-11-16
Node.js 2014这一年发生了什么
Node.js 的 2014 年充满了不幸和争议. 这一年 Noder 们经历了太多的伤心事, 经历了漫长的等待, 经历了沉重的分裂之痛. 也许 Noder 们不想回忆14年 Node.js land 发生的事情, 但正因为痛才更有铭记的价...
2015-11-12
JavaScript实现PC手机端和嵌入式滑动拼图验证码三种效果
PC和手机端网站滑动拼图验证码效果源码,同时包涵了弹出式Demo,使用ajax形式提交二次验证码所需的验证结果值,嵌入式Demo,使用表单形式提交二次验证所需的验证结果值,移动端手动实现弹出式Demo三种效果 首先要确认前端使用页面,比如...
2017-03-17
Angular2-primeNG文件上传模块FileUpload使用详解
近期在学习使用Angular2做小项目,期间用到很多primeNG的模块。 本系列将结合实战总结angular2-primeNG各个模块的使用经验。 文件上传模块FileUploadModule 首先要在使用该组件的模块内导入文件上传模块 ...
2017-03-09
React.js编程思想
JavaScript框架层出不穷,在很多程序员看来,React.js是创建大型、快速的Web应用的最好方式。这一款由Facebook出品的JS框架,无论是在Facebook还是在Instagram中,它的表现都非常出色。 使用React.j...
2015-11-12
回到顶部