React Router预备知识,关于history的那些事
原文 如果你想理解React Router,那么应该先理解history。更确切地说,是history这个为React Router提供核心功能的包。它能轻松地在客户端为项目添加基于location的导航,这种对于单页应用至关重要的功能。 npm install --save history 存在三类history,分别时browser,hash,与 memory。history包提供每种history的创建方法。 import { createBrowserHistory,createHashHistory,createMemoryHistory } from 'history' 如果你使用React Router,他会为你自动创建history对象,所以你并不需要与history进行直接的交互。不过,理解不同类型的history依旧很重要,这样你能在项目中决定究竟是用哪个。 history是什么?无论你创建哪种history,你最终都会得到一个几乎拥有相同属性与方法的对象。 locationhistory对象中最重要的属性就是location。location对象反映了当前应用所在的"位置"。其包含了 此外,每一个location都拥有一个与之关联且独一无二的 最后,location可以拥有与之相关的状态。这是一些固定的数据,并且不存在于URL之中。 { pathname: '/here',search: '?key=value',hash: '#extra-information',state: { modal: true },key: 'abc123' } 当创建一个history对象后,需要初始化location。对于不同类型history这一过程也不相同。例如,browser history会解析当前URL。 一个location控制所有?诚然我们只能访问当前location,history对象持续追踪着一组location。正因为拥有添加location并能够访问数组中任意location的能力,history才能被称为“历史”。如果history只能记录当前location,那就应该叫它“present”。 除了一组location外,history也保存一个索引值,用来指向当前所对应的location。 对于memory history,它们被直接定义。而对于browser history与hash history,数组与索引被浏览器所控制,并不能直接访问[注2]。 navigation方法可以说navigation方法是拥有location属性的history体系的点睛之笔。navigation允许你改变当前location。 push方法
默认情况下,当你点击 history.push({ pathname: '/new-place' }) replace
重定向时要使用 例如,当你在页面1通过点击link按钮导航到页面2,页面2可能会重定向到页面3。如果使用 history.replace({ pathname: '/go-here-instead' }) go,go,go最后有三个带‘go’的方法,它们分别是 history.goBack()
history.goForward()
history.go(-3) 监听!采用观察者模式,在location改变时,history会发出通知。每一个history对象都有listen方法,接受一个函数作为参数。这个函数会被添加到history储存的监听函数数组中。当location变化时(如代码调用history方法或用户点击浏览器按钮),history对象将会调用所有listener方法。这能让你在location变化时来设置代码更新。 const youAreHere = document.getElementById('youAreHere') history.listen(function(location) { youAreHere.textContent = location.pathname }) React Router的 链接事物Linking things together每一类history都拥有 const location = { pathname: '/one-fish',search: '?two=fish',hash: '#red-fish-blue-fish' } const url = history.createHref(location) const link = document.createElement('a') a.href = url // <a href='/one-fish?two=fish#red-fish-blue-fish'></a> 以上涵盖了基础的 结合在一起不同类型的history间还是存在差异的,这需要你去考虑选择一个适合你项目的history。 在浏览器中browser history与hash history都被用于浏览器环境。它们与history和location的web API进行交互,因此当前location与浏览器地址栏中展示的是相同的。 const browserHistory = createBrowserHistory() const hashHistory = createHashHistory() 它们两者的最大区别在于从URL创建location的方式。browser history使用完整URL[注3],而hash history只使用在第一个hash后的那部分URL。 // 提供如下URL url = 'http://www.example.com/this/is/the/path?key=value#hash' // browser history创建的location对象: { pathname: '/this/is/the/path',hash: '#hash' } //hash history创建的location对象: { pathname: 'hash',search: '',hash: '' } 使用哈希为何你需要hash history?理论上来说当你导航到一个URL时,服务端必有一个相应文件与之对应。对于动态服务,请求文件并不需要真实存在。相反,服务端会检查请求的URL并决定返回的HTML。 然而,静态文件服务可以直接返回存在磁盘中的文件。静态服务能做的最动态的事就是当URL制定目录时,从目录中返回 由于静态文件服务的这种限制,最简单的解决方案[注4]就是在服务端仅使用一个真实的location来返回用户端的获取需求。当然,仅有一个location意味着你的应用只有一个URL,这样就无法使用history。为了解决这一问题,hash history使用使用URL的哈希部分来读写location。 // 如果 example.com 使用静态资源服务,这三个URL都将从 // /my-site/index.html获取相同数据 http://www.example.com/my-site#/one http://www.example.com/my-site#/two // 然而由于使用hash history,应用中三者的location是不同的, // 因为location取决于URL的哈希部分 { pathname: '/one' } { pathname: '/two' } 纵然hash history运作良好,但由于其依赖将所有路径信息存在URL的哈希中,它被认为有可能遭到黑客攻击。因此当网站没有动态服务时再考虑使用它吧。 memory:缓存所有history使用memory location最棒的体验就是你可以在能使用JavaScript的地方随意使用。 一个简单的例子你可以通过运行Node在单元测试中使用它。这允许你能在不依赖浏览器运行的情况下测试代码。 更牛逼的是,memory history可以被使用在app中。在 你可以在浏览器中使用使用memory history,如果你愿意的话。(虽然这样你会失去与地址栏的交互能力)。 这memory history与其他两类history最大的区别在于其维护着自己的location。当创建memory history后你可以传入信息进行初始化状态。这个状态是一个location数组与当前location的索引[注5]。这与其他两类history是不同的,它们依赖浏览器来存储这个location数组。 const history = createMemoryHistory({ initialEntries: ['/','/next','/last'],initialIndex: 0 }) 使用history代替你来处理哪些相对繁琐且易错的是一个行之有效的方法。 无论你选择了何种类型的history,他们都是极易使用,并且拥有强大的能力进行导航与基于loaction的渲染。 注释[1] [2] 这是出于安全性的限制。在浏览器中history的location数组不仅包涵了访问过的location信息。如果开放浏览会泄漏使用者的浏览器历史信息,因此无法开放访问。 [3] m默认情况下,browser history创建的location对象,它的路径名是URL全路径名。当然,你可以为history定一个基础名,这样路径名中的这部分将会被忽略。 const history = createBrowserHistory({ basename: '/path' }) // 给出的路径 url: http://www.example.com/path/here // history对象将会创建如下location { pathname: '/here',... } [4] 理论上,可以让应用中的每个有效URL返回相同的HTML文件。虽然这可以事项,但如果所有的URL都是静态的,会产生大量冗余文件。不过任意地址都使用参数大量来匹配大量可能址是不可行的。 entries = [{ pathname: '/' }] index = 0 对于大部分应用这已经足够好了,但提前写入history对于恢复内容还是一个非常有用的方法。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |