React-router依赖于:history
一、概念理解
痛点:界面需要导航,需要根据不同的导航加载不同的模块
需要处理的问题:
1、URL地址栏
2、按需加载不同的模块(适当进行个性化处理)
其实,上面两个问题,并不难处理,但是本着抽象的原则,需要抽象出一个通用的模块。
React-router提供了一个良好的机制进行处理。
二、简单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} />;
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。