HashRouter.prototype.componentDidMount = function() { warning( !this.props.history, "<HashRouter> ignores the history prop. To use a custom history, " + "use `import { Router }` instead of `import { HashRouter as Router }`." ); }; }
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 }`." ); }; }
/** * The public API for putting history on context. */ classRouterextendsReact.Component { staticcomputeRootMatch(pathname) { return { path: "/", url: "/", params: {}, isExact: pathname === "/" }; }
// 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. this._isMounted = false; this._pendingLocation = null;
if (this.unlisten) { // Any pre-mount location changes have been captured at // this point, so unregister the listener. this.unlisten(); } if (!this.props.staticContext) { this.unlisten = this.props.history.listen(location => { if (this._isMounted) { this.setState({ location }); } }); } if (this._pendingLocation) { this.setState({ location: this._pendingLocation }); } }
/** * The public API for matching a single path and rendering. */ classRouteextendsReact.Component { render() { return ( <RouterContext.Consumer> {context => { invariant(context, "You should not use <Route> outside a <Router>");
const location = this.props.location || context.location; const match = this.props.computedMatch ? 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) && isEmptyChildren(children)) { children = null; }
if (hashChanged) { // We cannot tell if a hashchange was caused by a PUSH, so we'd // rather setState here and ignore the hashchange. The caveat here // is that other hash histories in the page will consider it a POP. ignorePath = path; pushHashPath(encodedPath);
setState({ action, location }); } else { warning( false, 'Hash history cannot PUSH the same path; a new entry will not be added to the history stack' );
globalHistory.pushState(historyState, "", url); 这里就很清楚的看到 5.x 的 hash 是使用 history api 来操作的,所以 state 将和 Browser 一致会保存,也可 window.history log 出来
functionpush(to: To, state?: any) { let nextAction = Action.Push; let nextLocation = getNextLocation(to, state); functionretry() { push(to, state); }
warning( nextLocation.pathname.charAt(0) === "/", `Relative pathnames are not supported in hash history.push(${JSON.stringify( to )})` );
if (allowTx(nextAction, nextLocation, retry)) { let [historyState, url] = getHistoryStateAndUrl(nextLocation, index + 1);
// TODO: Support forced reloading // try...catch because iOS limits us to 100 pushState calls :/ try { globalHistory.pushState(historyState, "", url); } catch (error) { // They are going to lose state here, but there is no real // way to warn them about it since the page will refresh... window.location.assign(url); }