2

React-router依赖于:history

一、概念理解

痛点:界面需要导航,需要根据不同的导航加载不同的模块
需要处理的问题:
1、URL地址栏
2、按需加载不同的模块(适当进行个性化处理)
其实,上面两个问题,并不难处理,但是本着抽象的原则,需要抽象出一个通用的模块。
React-router提供了一个良好的机制进行处理。

clipboard.png

二、简单Demo

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

三、源码解析

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 <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里面

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

joytime
44 声望2 粉丝