ReactRouter implementation describe Browser History location / { try_files $uri $uri/ /index.html; } Hash History The Memory History const history = createMemoryHistory(location); accomplish Let's implement a very simple <!-- Browser History --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Router</title> </head> <body> <ul> <li><a href="/home" rel="external nofollow" >home</a></li> <li><a href="/about" rel="external nofollow" >about</a></li> <div id="routeView"></div> </ul> </body> <script> function Router() { this.routeView = null; // component-hosted view container this.routes = Object.create(null); // defined routes } // Bind route matching event Router.prototype.route = function (path, callback) { this.routes[path] = () => this.routeView.innerHTML = callback() || ""; }; // InitializeRouter.prototype.init = function(root, rootView) { this.routeView = rootView; //Specify the view container this.refresh(); //Initialize and refresh the view root.addEventListener("click", (e) => { //Event delegation to root if (e.target.nodeName === "A") { e.preventDefault(); history.pushState(null, "", e.target.getAttribute("href")); this.refresh(); // Trigger to refresh the view} }) // Listen for user clicks on back and forward // pushState and replaceState will not trigger the popstate event window.addEventListener("popstate", this.refresh.bind(this), false); }; // Refresh the viewRouter.prototype.refresh = function () { let path = location.pathname; console.log("refresh", path); if(this.routes[path]) this.routes[path](); else this.routeView.innerHTML = ""; }; window.Router = new Router(); Router.route("/home", function() { return "home"; }); Router.route("/about", function () { return "about"; }); Router.init(document, document.getElementById("routeView")); </script> </html> <!-- Hash History --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Router</title> </head> <body> <ul> <li><a href="#/home" rel="external nofollow" >home</a></li> <li><a href="#/about" rel="external nofollow" >about</a></li> <div id="routeView"></div> </ul> </body> <script> function Router() { this.routeView = null; // component-hosted view container this.routes = Object.create(null); // defined routes } // Bind route matching event Router.prototype.route = function (path, callback) { this.routes[path] = () => this.routeView.innerHTML = callback() || ""; }; // InitializeRouter.prototype.init = function(root, rootView) { this.routeView = rootView; //Specify the view container this.refresh(); //Initialization trigger //Listen for hashchange events to refresh window.addEventListener("hashchange", this.refresh.bind(this), false); }; // Refresh the viewRouter.prototype.refresh = function () { let hash = location.hash; console.log("refresh", hash); if(this.routes[hash]) this.routes[hash](); else this.routeView.innerHTML = ""; }; window.Router = new Router(); Router.route("#/home", function() { return "home"; }); Router.route("#/about", function () { return "about"; }); Router.init(document, document.getElementById("routeView")); </script> </html> analyze
// packages\react-router-dom\modules\HashRouter.js line 10 class BrowserRouter extends React.Component { history = createHistory(this.props); render() { return <Router history={this.history} children={this.props.children} />; } } Next we go to // line packages\react-router\modules\Router.js line 10 class Router extends React.Component { static computeRootMatch(pathname) { return { path: "/", url: "/", params: {}, isExact: pathname === "/" }; } constructor(props) { super(props); this.state = { location: props.history.location }; // 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 (!props.staticContext) { this.unlisten = props.history.listen(location => { if (this._isMounted) { this.setState({ location }); } else { this._pendingLocation = location; } }); } } componentDidMount() { this._isMounted = true; if (this._pendingLocation) { this.setState({ location: this._pendingLocation }); } } componentWillUnmount() { if (this.unlisten) this.unlisten(); } render() { return ( <RouterContext.Provider children = {this.props.children || null} value={{ history: this.props.history, location: this.state.location, match: Router.computeRootMatch(this.state.location.pathname), staticContext: this.props.staticContext }} /> ); } } When we use it, we use // \packages\react-router\modules\Route.js line 17 class Route extends React.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) && children.length === 0) { children = null; } if (typeof children === "function") { children = children(props); // ... } return ( <RouterContext.Provider value={props}> {children && !isEmptyChildren(children) ? children : props.match ? component React.createElement(component, props) : render ? render(props) : null : null} </RouterContext.Provider> ); }} </RouterContext.Consumer> ); } } In fact, the tag we probably write the most is the // packages\react-router-dom\modules\Link.js line 14 class Link extends React.Component { handleClick(event, history) { if (this.props.onClick) this.props.onClick(event); 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(); const method = this.props.replace ? history.replace : history.push; method(this.props.to); } } render() { const { innerRef, replace, to, ...rest } = this.props; // eslint-disable-line no-unused-vars return ( <RouterContext.Consumer> {context => { invariant(context, "You should not use <Link> outside a <Router>"); const location = typeof to === "string" ? createLocation(to, null, null, context.location) : to; const href = location ? context.history.createHref(location) : ""; return ( <a {...rest} onClick={event => this.handleClick(event, context.history)} href={href} ref={innerRef} /> ); }} </RouterContext.Consumer> ); } } Daily Question https://github.com/WindrunnerMax/EveryDay refer to https://zhuanlan.zhihu.com/p/44548552 https://github.com/fi3ework/blog/issues/21 https://juejin.cn/post/6844903661672333326 https://juejin.cn/post/6844904094772002823 https://juejin.cn/post/6844903878568181768 https://segmentfault.com/a/1190000014294604 https://github.com/youngwind/blog/issues/109 http://react-guide.github.io/react-router-cn/docs/guides/basics/Histories.html This is the end of this article about the implementation method of ReactRouter. For more information about the implementation of ReactRouter, please search for previous articles on 123WORDPRESS.COM or continue to browse the following related articles. I hope you will support 123WORDPRESS.COM in the future! You may also be interested in:
|
<<: MySQL 5.7.16 free installation version graphic tutorial under Linux
>>: Detailed explanation of how to cleanly uninstall Docker
You need to add "gt_" in front of the f...
Table of contents Project Background Improvement ...
Preface In a recent project, we need to save a la...
This article uses an example to describe the solu...
# Adjust VMware hard disk boot priority Step 1: E...
Table of contents 1.kvm deployment 1.1 kvm instal...
Table of contents 1. Create a table 1.1 Create te...
Preface When I was writing a small project yester...
Table of contents 1. Filter unique values 2. Shor...
This article shares the implementation method of ...
Based on SEO and security considerations, a 301 r...
1. For comparison of date size, the date format p...
Table of contents Download the compressed file Ad...
Operating system: windowns10_x64 Python version: ...
1. Trash or Classic? Web technology updates very ...