React-router


React-router依存于:history
一、概念理解
  :      ,                
       :
1、URL   
2、         (         )
  ,      ,     ,         ,            。
React-router              。
二、簡単デモ

    
        
            
            
        
    
)
三、ソース解析
1、RouterとRoute
    Route:パスにマッチしてレンダリングします.
//         ,        ,  github
class Route extends React.Component(){
    constructor(){
        this.state={
            match:this.computeMatch(this.props, this.context.router)
        }
    }
    //                            
    static propTypes = {
        computedMatch: PropTypes.object, // private, from 
        path: PropTypes.string,
        exact: PropTypes.bool,
        strict: PropTypes.bool,
        sensitive: PropTypes.bool,
        component: PropTypes.func,
        render: PropTypes.func,
        children: PropTypes.oneOfType([PropTypes.func, PropTypes.node]),
        location: PropTypes.object
    };
    //        ,       
    componentWillReceiveProps(nextProps,nextContext){
        this.setState({
            match: this.computeMatch(nextProps, nextContext.router)
        });
    }
    render(){
        //  
            if (component) return match ? React.createElement(component, props) : null;

    }
}
    Router:historyを全体のcontextに入れます.
class Router extends React.Component {
    //      history
    static propTypes = {
        history: PropTypes.object.isRequired,
        children: PropTypes.node
    };
    //      ,render     
    render() {
        const { children } = this.props;
        return children ? React.Children.only(children) : null;
      }
}
2、Switch、Redirect
//switch    
    let match, child;
    React.Children.forEach(children, element => {
      if (match == null && React.isValidElement(element)) {
        const {
          path: pathProp,
          exact,
          strict,
          sensitive,
          from
        } = element.props;
        const path = pathProp || from;

        child = element;
        match = matchPath(
          location.pathname,
          { path, exact, strict, sensitive },
          route.match
        );
      }
    });

    return match
      ? React.cloneElement(child, { location, computedMatch: match })
      : null;
      
//Redirect    
componentDidUpdate(prevProps) {
    const prevTo = createLocation(prevProps.to);
    const nextTo = createLocation(this.props.to);
    this.perform();
  }

  computeTo({ computedMatch, to }) {
    if (computedMatch) {
      if (typeof to === "string") {
        return generatePath(to, computedMatch.params);
      } else {
        return {
          ...to,
          pathname: generatePath(to.pathname, computedMatch.params)
        };
      }
    }

    return to;
  }

  perform() {
    const { history } = this.context.router;
    const { push } = this.props;
    const to = this.computeTo(this.props);

    if (push) {
      history.push(to);
    } else {
      history.replace(to);
    }
  }
3、HashRouter、BrowserRouter:Routerをベースにしています.
//HashRouter     
import { createHashHistory as createHistory } from "history";

class HashRouter extends React.Component {
  static propTypes = {
    basename: PropTypes.string,
    getUserConfirmation: PropTypes.func,
    hashType: PropTypes.oneOf(["hashbang", "noslash", "slash"]),
    children: PropTypes.node
  };

  history = createHistory(this.props);

  render() {
    return ;
  }
}

//BrowserRouter      
import { createBrowserHistory as createHistory } from "history";

class BrowserRouter extends React.Component {
  static propTypes = {
    basename: PropTypes.string,
    forceRefresh: PropTypes.bool,
    getUserConfirmation: PropTypes.func,
    keyLength: PropTypes.number,
    children: PropTypes.node
  };

  history = createHistory(this.props);

  render() {
    return ;
  }
}