/** * The public API for a <Router> that uses HTML5 history. * 公开一个基于 HTML5 history 的 api <Router> */ classBrowserRouterextendsReact.Component { history = createHistory(this.props);
BrowserRouter.prototype.componentDidMount = function() { warning( !this.props.history, "<BrowserRouter> ignores the history prop. To use a custom history, " + "use `import { Router }` instead of `import { BrowserRouter as Router }`." ); }; }
exportdefaultBrowserRouter;
这个组件,非常简单,通过引入和初始化 history 包来获得一个 history 对象, 然后在 componentDidMount 生命周期中添加了一个检查, 这个检查是判断 props 中是否有 history 属性,如果存在的话,那么就弹出一个警告, 如果要使用自定义 history 对象那么就需要使用 import {Router} from 'react-router-dom’来使用. 最后这个组件返回了 react-router 包中的 Router 组件.
// This is a bit of a hack. We have to start listening for location // changes here in the constructor in case there are any <Redirect>s // on the initial render. If there are, they will replace/push when // they mount and since cDM fires in children before parents, we may // get a new location before the <Router> is mounted.
/** * The public API for rendering the first <Route> that matches. * Switch 组件渲染第一个符合条件的 Route 组件 */ classSwitchextendsReact.Component { render() { return ( <RouterContext.Consumer> {" "} // 订阅 context {context => { invariant(context, "You should not use <Switch> outside a <Router>"); // 检查context是否存在
// We use React.Children.forEach instead of React.Children.toArray().find() // here because toArray adds keys to all child elements and we do not want // to trigger an unmount/remount for two <Route>s that render the same // component at different URLs. // 通过React 提供的children的方法遍历children, React.Children.forEach(this.props.children, child => { if (match == null && React.isValidElement(child)) { // 如果 match 为空而且 child是react组件 element = child;
/** * The public API for matching a single path and rendering. * Route 组件, 根据path进行渲染 */ classRouteextendsReact.Component { render() { return ( <RouterContext.Consumer> {" "} // context {context => { invariant(context, "You should not use <Route> outside a <Router>"); // 判断顶级是否存在 Router 组件,如果不存在进行报错,
const location = this.props.location || context.location; //获得location const match = this.props.computedMatch // 判断 是否存在 computedMatch 对象, computedMatch对象是Switch组件传递下来的, 如果存在就使用如果不存在那么自己解析 ? this.props.computedMatch // <Switch> already computed the match for us : this.props.path ? matchPath(location.pathname, this.props) : context.match;
const props = { ...context, location, match };
let { children, component, render } = this.props;
// Preact uses an empty array as children by // default, so use null if that's the case. if (Array.isArray(children) && children.length === 0) { // 判断children是否为一个数组 ,api要求是一个函数 children = null; }
if (typeof children === "function") { // 判断children是否是一个函数 children = children(props); //如果是就将props传递给它 然后由children函数自己决定渲染
/** * The public API for rendering a history-aware <a>. */ classLinkextendsReact.Component { handleClick(event, history) { try { if (this.props.onClick) this.props.onClick(event); } catch (ex) { event.preventDefault(); throw ex; }
if ( !event.defaultPrevented && // onClick prevented default event.button === 0 && // ignore everything but left clicks (!this.props.target || this.props.target === "_self") && // let browser handle "target=_blank" etc. !isModifiedEvent(event) // ignore clicks with modifier keys ) { event.preventDefault();