React-router

React-router依賴於:historynode

1、概念理解

痛點:界面須要導航,須要根據不一樣的導航加載不一樣的模塊
須要處理的問題:
一、URL地址欄
二、按需加載不一樣的模塊(適當進行個性化處理)
其實,上面兩個問題,並不難處理,可是本着抽象的原則,須要抽象出一個通用的模塊。
React-router提供了一個良好的機制進行處理。

clipboard.png

2、簡單Demo

<HashRouter>
    <Layout>
        <Switch>
            <Redirect exact path="/" to={}/>
            <Route/>
        </Switch>
    </Layout>
</HashRouter>)

3、源碼解析

一、Router和Route

    Route:匹配路徑,並進行渲染git

//代碼是部分代碼模塊,若是想看真的源碼,移步github
class Route extends React.Component(){
    constructor(){
        this.state={
            match:this.computeMatch(this.props, this.context.router)
        }
    }
    //這部分的目的主要是讓你們瞭解下源碼中須要輸入的參數和類型
    static propTypes = {
        computedMatch: PropTypes.object, // private, from <Switch>
        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裏面github

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;
      }
}

二、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);
    }
  }

三、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 <Router history={this.history} children={this.props.children} />;
  }
}

//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 <Router history={this.history} children={this.props.children} />;
  }
}
相關文章
相關標籤/搜索