0x000 概述

上一章使用的是自己实现的route,当然已经有现成的库给我们用了,那就是react-route

0x001 history Api说明

在说这个库之前,得先对history新的api做一个了解

  1. window.history.pushState(data,title,?url)

    • data:数据
    • title:标题
    • url:地址

      当我们调用该函数的时候,将改变地址栏的地址,但是却不会导致页面重新去后台获取,如下图操作,在第一次初始化完成之后,我们依次调用

      window.history.pushState({name:'a'},'','a')
      window.history.pushState({name:'b'},'','b')
      window.history.pushState({name:'c'},'','c')
      window.history.pushState({name:'d'},'','d')

      将会看到地址栏分别变成了:

      https://github.com/a
      https://github.com/b
      https://github.com/c
      https://github.com/d

      但是网络请求却没有发出

      clipboard.png

  2. window.history.state:该变量可以获取到跳转当前所处state时传入的data:

    clipboard.png

  3. window.onpopstate:这是一个事件,可以设置监听器,监听状态被pop出来的时候的事件,其中goback会触发该事件

    clipboard.png

  4. 总结
    根据以上几个特性,就可以和上一章一样,做出一个基于history模式的路由库了

0x002 history库说明

history是一个针对该特性封装的库,以下是示例代码

import createHistory from 'history/createBrowserHistory'

const history = createHistory()

// 监听 location 的变化
const unlisten = history.listen((location, action) => {
    // location is an object like window.location
    console.log(action, location.pathname, location.state)
})
// 修改 location
history.push("/home", { some: "state" })
// 取消监听
unlisten()

查看浏览器

clipboard.png

0x003 react-route

react-route+history+react就可以形成一个套餐了
  • 源码

    import React from 'react'
    import ReactDom from 'react-dom'
    import { Router, Route, Switch,withRouter } from 'react-router'
    import createHistory from 'history/createBrowserHistory'
    
    class App extends React.Component{
        render(){
            console.log(this)
            return(
                <div>
                    <div>
                        <button className="btn btn-primary" onClick={()=>{this.props.history.push('/index')}}>首页</button>
                        <button className="btn btn-primary" onClick={()=>{this.props.history.push('/article')}}>文章</button>
                        <button className="btn btn-primary" onClick={()=>{this.props.history.push('/mine')}}>我的</button>
                    </div>
                    <hr/>
                    <Switch>
                        <Route path='/index' component={()=>({render:()=><p>首页</p>})}></Route>
                        <Route path='/article' component={()=>({render:()=><p>文章</p>})}></Route>
                        <Route path='/mine' component={()=>({render:()=><p>我的</p>})}></Route>
                    </Switch>
                </div>
            )
        }
    }
    
    const history = createHistory()
    
    let MyApp=withRouter(App)
    
    ReactDom.render(
        <Router history={history}>
            <MyApp/>
        </Router>,
        document.getElementById('app')
    )
  • 效果
    图片描述
  • 说明

    1. App组件说明
      App组件是跟组件,所有的组件都挂载在这个组件之下,在这个组件中,使用了两个react-route的组件,一个是Switch,用来在路由变化的时候切换显示的路由;一个是Route组件,一个Route代表一个页面,也代表一个组件,这里用了三个Route,每个Route对应一个路由,也对应一个组件,这里的组件为了方便,直接用匿名函数实现,分别是:

      ()=>({render:()=><p>首页</p>}) // 对应`/index`
      ()=>({render:()=><p>文章</p>}) // 对应`/article`
      ()=>({render:()=><p>我的</p>}) // 对应`/mine`

      当我们点击相应的按钮的时候,将会调用this.props.history.push('${path}')来跳转到对应的页面,其中${path}是我们设置的Route组件的path属性。

    2. history
      通过history库来做location监听和跳转
    3. withRoute是一个HOC,为App组件注入了history对象和路由相关的属性,这样可以屏蔽路由的存在,将App组件变成一个纯粹的组件
    4. Router组件接管了histoy对象,在该组件中完成了history的监听和路由的渲染

0x004 react-route-dom

上面的调用太复杂了,需要手动创建history、调用this.props.history.push('/index')跳转,那有没有简单点的呢?那就是react-router-dom,这个库封装了react-routehistory库,并提供了几个实用的组件
  • 源码

import React from 'react'
import ReactDom from 'react-dom'
import {BrowserRouter, Switch, Route, Link, withRouter} from 'react-router-dom'

class App extends React.Component {
    render() {
        return (
            <div>
                <div>
                    <Link to='/index'>首页</Link>
                    <Link to='/article'>文章</Link>
                    <Link to='/mine'>我的</Link>
                </div>
                <hr/>
                <Switch>
                    <Route path='/index' component={() => ({render: () => <p>首页</p>})}></Route>
                    <Route path='/article' component={() => ({render: () => <p>文章</p>})}></Route>
                    <Route path='/mine' component={() => ({render: () => <p>我的</p>})}></Route>
                </Switch>
            </div>
        )
    }
}

let MyApp = withRouter(App)


ReactDom.render(
    <BrowserRouter>
        <MyApp/>
    </BrowserRouter>,
    document.getElementById('app')
)
  • 说明:

    1. 使用BrowserRouter替代Router,并且不再手动创建history
    2. 使用Link直接跳转
    3. 该库是在react-routehistory库的基础之上封装的,只是为了在dom环境下快速调用,并且提供了一个更加实用的组件而已,不能应为这个库而忘记了本质。

0x005 总结

看透它,然后掌握它

0x006 资源


followWinter
1.5k 声望82 粉丝

暂时没有