react-router 4.x(路由)

来源:互联网 发布:dm软件 编辑:程序博客网 时间:2024/06/04 19:57

一、react-router


1.安装

npm install react-router-dom --save

2.使用,我们直接上菜,想必大家已经饿了。

//index.jsimport "../css/reset.css";import "../css/common.css";import React,{ Component } from "react";import { render } from "react-dom";import {    BrowserRouter as Router,    Route,    Link}from 'react-router-dom';import App from "../Components/app";import Shop from "../Components/shop.js";import Owner from "../Components/owner.js";class Hello extends Component{    render(){        return (            <Router>                <div>                    <ul>                        <li><Link to="/">App</Link></li>                        <li><Link to="/shop">Shop</Link></li>                        <li><Link to="/owner">Owner</Link></li>                    </ul>                    <hr />                    <Route exact path="/" component={App} />                    <Route path="/shop" component={Shop} />                    <Route path="/owner" component={Owner} />                </div>            </Router>        )    }}render(    <Hello />,    document.getElementById('root'))

和之前的版本一样,Router还是一个容器,但他的角色却改变了,4.0的react-router可以任意的放标签了,这意味着使用方式的改变,但真正的路由通过Route定义。Link标签依然可以看作a标签。点击会改变浏览器Url的hash值,通过Route标签来捕获这个url并返回component属性中定义的组件。Route标签内有个exact关键字,它是用来将”/”做唯一的匹配。如果没有这个的话,在匹配其他的同时也会匹配到当前。一试便知。
通过Router路由的组件可以拿到一个match参数,这个参数是一个对象。其中包含几个数据:
isExact: 刚才已经说过这个关键字,表示是为做全等匹配。
params: path中包含的一些额外数据。
path: Route组件path属性的值。
url: 实际url的hash值。
3.Router标签

hashHistory 老版本浏览器的historybrowserHistory h5的historymemoryHistory node环境下的history,存储在memory中。

4.Route标签
在例子中你可能注意到了Route的几个prop

exactpathcomponentrender

他们都不是必填项,如果path没有赋值,那么此Route就是默认渲染的。
Route的作用就是当url和Route中path属性的值匹配时,就渲染component中的组件或者render中的内容。

说到这,那么Route内部是怎样实现这个机制的呢,不难猜测肯定是用一个匹配的方法来实现的,那么Router是怎么知道url更新了然后重新进行匹配并且渲染呢?
整理一下思路,在一个web应用中,改变一个url无非两种方式。一种是利用超链接进行跳转,另一种是使用浏览器的前进后退功能,前者在触发Link的跳转事件之后再触发。后者是Route利用的history的listen方法来监听url的变化。为了防止引入新的库,Route创作者选择使用html5中的popState事件。只要点击了浏览器的前景或者后退按钮,这个事件就会触发,我们来看一下Route的代码。

class Route extends Component {  static propTypes: {    path: PropTypes.string,    exact: PropTypes.bool,    component: PropTypes.func,    render: PropTypes.func,  }  componentWillMount() {    addEventListener("popstate", this.handlePop)  }  componentWillUnmount() {    removeEventListener("popstate", this.handlePop)  }  handlePop = () => {    this.forceUpdate()  }  render() {    const {      path,      exact,      component,      render,    } = this.props    //location是一个全局变量    const match = matchPath(location.pathname, { path, exact })    return (      //有趣的是从这里我们可以看出各属性渲染的优先级,component第一      component ? (        match ? React.createElement(component, props) : null      ) : render ? ( // render prop is next, only called if there's a match        match ? render(props) : null      ) : children ? ( // children come last, always called        typeof children === 'function' ? (          children(props)        ) : !Array.isArray(children) || children.length ? ( // Preact defaults to empty children array          React.Children.only(children)        ) : (              null            )      ) : (              null            )    )  }}

Route在组件将要Mount的时候,添加popState事件的监听,每当popState事件触发,就使用forceUpdate强制刷新,从而基于当前的location.pathname进行一次匹配。再根据结果渲染。

  componentWillMount() {    addEventListener("popstate", this.handlePop)  }  handlePop = () => {    this.forceUpdate()  }