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