開始學習React-Router v4 —— Histories

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

    • pathname: URL 路徑字段
    • search:URL 查詢字段
    • hash:URL 的 hash 字段
    • state:路徑的狀態,只在 browser 和 memory history 中有效。
    • push(path, [state]):將狀態路徑壓入 history 棧。
    • replace(path, [state]):替換當前的狀態路徑。
    • go(n):向前移動當前指針 n 次。
    • goBack():go(-1)
    • goForward():go(1)
    • block(prompt):暫時阻止導航(「您肯定離開」)。

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

相關文章
相關標籤/搜索