如果你想理解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对象反映了当前应用所在的"位置"。其包含了pathname,search[注1],hash这种由'URL'派生出的属性。
此外,每一个location都拥有一个与之关联且独一无二的key。'key'用于特定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方法
push方法使能你跳转到新的location。通过在当前location后添加新的location时,任意的'未来'location会被清除(之前由后退按钮而形成的在当前location后的location)。
默认情况下,当你点击<Link>时,会调用history.push方法进行导航。
history.push({ pathname: '/new-place' })
replace
replace方法与push相似,但它并非添加location,而是替换当前索引上的位置。'未来'location将不会被清除。
重定向时要使用replace。这也是React Router的<Redirect>组件中使用的方法。
例如,当你在页面1通过点击link按钮导航到页面2,页面2可能会重定向到页面3。如果使用push方法,点击放回按钮将从页面3返回到页面2(这里有潜在的可能再重定向到页面3)。如果使用replace方法,会从页面三直接返回页面1。
history.replace({ pathname: '/go-here-instead' })
go, go, go
最后有三个带‘go'的方法,它们分别是goBack,goForward与go。
goBack返回一层页面。实际上是将history的索引值减1。
history.goBack()
goForward与goBack相对。向前一层页面。这仅在拥有'未来'location生效,即当用户点击了后退按钮。
history.goForward()
go是一个强大的方法,并包含了goForward与goBack的功能。传入负数则退后,传入正数则向前。
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的router组件将会订阅history对象,这样当location变化时,其能重新渲染。
链接事物Linking things together每一类history都拥有createHref方法,其使用location对象,输出URL。
内部,history通过location对象进行导航。然而像锚点元素(a),它并不知道history这个包,也不知道location对象是什么。为了能让生成的HTML 在不需要history的情况下,依旧能够导航。我们必须生成真的URL。
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 API。虽然还有其他未介绍的属性与方法,但上述方法能够是你明白history对象是如何运作的。
结合在一起