当前的分析版本是 v52.0,最新提交为:项目由 lerna 管理,在根目录下执行yarn
您可以为项目安装依赖项。 继续在根目录下执行yarn build
会进入 reaact-router、react-router-dom 等目录进行打包,打包工具是 rollup,会打包 esm、cjs、umd 等结果。
react-router-dom:软件包 react-router-dom
/users/songjp/fe/mime/react-router/packages/react-router-dom├──browserrouter.js├──hashrouter.js├──link.js├──memoryrouter.js├──n**link.js├──prompt.js├──readme.md├──redirect.js├──route.js├──router.js├──staticrouter.js├──switch.js├──es| ├browserrouter.js| ├hashrouter.js| ├link.js| ├memoryrouter.js| ├n**link.js| ├prompt.js| ├redirect.js| ├route.js| ├router.js| ├staticrouter.js| ├switch.js| ├generatepath.js| ├matchpath.js| ├warnaboutdeprecatedesmimport.js| └withrouter.js├──generatepath.js├──index.js├──jest.config.js├──matchpath.js├──modules| ├browserrouter.js| ├hashrouter.js| ├link.js| ├n**link.js| ├index.js| └utils├──package.json├──rollup.config.js├──warnaboutdeprecatedcjsrequire.js└──withrouter.js
您可能会有疑问:
为什么根目录下有浏览器路由器?js,还有es browserrouterjs 和模块 BrowserRouterjs ?为什么根目录下有路由器?js,有es路由器js,但没有模块路由器JS直接说出了结论:
汇总根据模块索引打包js 打包,即源码在 modules 目录下,react-router-dom 的源码在 modules 目录下,主要是 browserrouter、hashrouter、link、n**link 组件,至于 router 组件、switch 组件等,其实在 react-router 仓库里。 至于根目录下的browserrouterjs 主要是为了兼容性require("react-router-dom/%s")
实际上应该更多地使用require("react-router-dom").%s
es 目录js 主要是为了兼容性import %s from "react-router-dom/es/%s
这样的引用方式,其实更值得推荐import from "react-router-dom"
引用的方式是只要注意 modules 目录,es 目录下的文件和根目录下的文件都是为了兼容一些组件引用
通常我们像这样使用 react-router-dom:
import from "./react-router-dom"; home about users
让我们从browserrouter组件开始。
// react-router-dom/browserrouter.jsimport from "history";class browserrouter extends react.component }
browserrouter 组件实际上通过调用 history 中的 createbrowserhistory 方法来创建一个 history 对象。 历史记录中有一个 CreateTransitionManager 文件,它在内部实现了观察者模式:// history/createtransitionmanager.jslet listeners = const appendlistener = (fn) => listeners.push(listener) return ()=> }const notifylisteners = (.args) =>
当 history 对象本身触发 popstate 事件或历史记录时替换或历史记录push 方法,notifylisteners 被触发以通知所有观察者。
而 react-router 中的 router 组件实际上是它是观察者。它内部有一个位置状态,并且它订阅了历史记录更改
// react-router/router.jsif (!props.staticcontext) )else }
当历史记录更改时,位置的状态也会更改。 此状态也用作 routercontext提供者将继续传递。
// react-router/router.js
作为一个真正的路由组件(渲染组件),它在内部确定从 routercontext 传递的位置值,以及它自己的路径(例如确定是否存在匹配项:// react-router/route.jsconst match = this.props.computedmatch? this.props.computedmatch // already computed the match for us: this.props.path? matchpath(location.pathname, this.props): context.match;
匹配呈现子项:// react-router/route.js
从上面可以看出,支持各种孩子。 对应路由组件的组件参数、渲染参数和子参数。
在 BrowserRouter 的情况下,它只是将 CreateBrowserHistory 替换为 CreateHashHistory,因此最终的逻辑差异在于 npm 包 History。
// react-router-dom/hashrouter.jsimport react from "react";import from "history";class hashrouter extends react.component }export default hashrouter;
hashrouter 与 browserrouter 有什么共同点:
当我们点击链接组件进行跳转时,我们调用其中的推送方法(browserrouter 或 hashrouter)来更改 url。 对于历史模式,它是通过历史PushState,对于哈希模式,是更改窗口location.hash。在各自的推送方法中,它们会调用内部的 setstate 方法,该方法会通知每个底层路由组件最新的路由信息,每个路由组件会通过匹配最新的路由信息来判断是否需要显示。 hashrouter 和 browserrouter 之间的区别:
什么时候回滚前进的路由时间:历史模式主要是监听popstate事件,获取最新的路由信息(不,其实在触发popstate的时候,url已经变了,所以直接把url信息传递给路由),然后通过setstate通知路由组件。 请注意,popstate 事件称为历史记录pushstate() 和历史replaceState() 不执行,但仅在历史记录时执行back(),history.go(),history.forward() (当单击浏览器后退按钮时,它实际上等同于调用历史记录。back(),所以 popstate 事件也会被触发)。参考:PopState MDN:对于hash模式,主要监听hashchange事件,获取最新的路由信息(同上),通过setstate通知路由组件。