React-router依赖于:historynode
痛点:界面须要导航,须要根据不一样的导航加载不一样的模块 须要处理的问题: 一、URL地址栏 二、按需加载不一样的模块(适当进行个性化处理) 其实,上面两个问题,并不难处理,可是本着抽象的原则,须要抽象出一个通用的模块。 React-router提供了一个良好的机制进行处理。
<HashRouter> <Layout> <Switch> <Redirect exact path="/" to={}/> <Route/> </Switch> </Layout> </HashRouter>)
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核心模块 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源码很简单 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} />; } }