React Router 是創建在 history 之上的。 簡而言之,一個 history 知道如何去監聽瀏覽器地址欄的變化, 並解析這個 URL 轉化爲 location 對象, 而後 router 使用它匹配到路由,最後正確地渲染對應的組件。react
history 是 React-Router 極少的依賴模塊之一,它主要做用是在不一樣的環境下管理會話。常常會使用到的 history 有:bootstrap
browser history:DOM 的具體應用,支持 HTML5 的 history API。瀏覽器
hash history:DOM 的具體應用,用以兼容老版本的瀏覽器。bash
memory history:在無 DOM 或測試環境下經過內存方式處理來實施,適合 React-Native。 和history 對象相關的主要屬性和方法有:react-router
length:history 棧中的狀態路徑個數。dom
action:當前的操做,字符串形式(PUSH, REPLACE, POP)測試
location:當前的狀態路徑。ui
history 是可變的,所以狀態路徑的訪問方式推薦使用 的屬性(props)裏間接獲取,而不是直接使用 history.location。這能夠保證在 React 生存週期裏可以得到正確的比較。this
index.jsurl
import React,{Component} from 'react';
import ReactDOM from 'react-dom';
import { HashRouter as Router, Route, Switch} from './react-router-dom'
import 'bootstrap';
import App from './components/App'
import User from './components/User';
import Login from './components/Login';
import Protected from './components/Protected'
let Home = (props,context)=>{
console.log(props,context)
return <div>首頁</div>
}
//let User = ()=><div>用戶管理</div>
let Profile = ()=><div>我的設置</div>
ReactDOM.render(
<App>
<Route path="/home" component={Home} />
<Route path="/user" component={User} />
<Route path="/login" component={Login} />
<Protected path="/profile" component={Profile} />
</App>
,document.querySelector('#root')
)
/**
*
{
history:{
push()
},
location:{pathname:'/home'},
match{
params:{},
path:'/home',
url:'/home'
}
}
url /user/datail/1
path /user/datail/:id
params= {}
*/
複製代碼
HashRouter.js
import React,{Component} from 'react';
import PropTypes from 'prop-types';
export default class HashRouter extends Component{
static childContextTypes = {
location:PropTypes.object,
history:PropTypes.object
}
constructor(props){
super(props)
this.state = { location: { pathname: window.location.hash.slice(1) || '/' }, state: {} };
}
getChildContext() {
let that = this
return {
location: this.state.location,
history: {
push(path) {
if (typeof path == 'object') {
let { pathname, state } = path;
that.setState({
location: { ...that.state.location, state }
}, () => {
console.log('this.state.location.state', that.state.location.state);
window.location.hash = pathname;
});
} else {
window.location.hash = path;
}
}
}
}
}
componentDidMount(){
window.location.hash = window.location.hash || '/'
let render = ()=>{
this.setState({ location: { ...this.state.location, pathname: window.location.hash.slice(1) || '/' } });
}
window.addEventListener('hashchange',render)
}
render(){
return this.props.children
}
}
複製代碼
Route.js
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import pathToRegexp from 'path-to-regexp';
export default class Route extends Component {
constructor(props) {
super(props);
let { path } = props;// /user/detail/:id
this.keys = [];
this.regexp = pathToRegexp(path, this.keys, { end: false });
this.keys = this.keys.map(key => key.name);
}
static contextTypes = {
location: PropTypes.object,
history: PropTypes.object
}
render() {
let { path, component: Component, render, children } = this.props;
let { location } = this.context;
let result = location.pathname.match(this.regexp);
let props = {
location,
history: this.context.history
}
if (result) {
let [url, ...values] = result;
props.match = {
url,
path,
params: this.keys.reduce((memo, key, idx) => {
memo[key] = values[idx];
return memo;
}, {})
}
if (Component) {
return <Component {...props} />
} else if (render) {
return render(props);
} else if (children) {
return children(props);
} else {
return null;
}
} else {
if (children) {
return children(props);
} else {
return null;
}
}
}
}
複製代碼
history Hash 的關鍵是context