官方英文文档 - https://reacttraining.com/rea...
版本 -v4.2.0
本文档中的术语 history
指的是 history 包,它是 React Router 的两个主要依赖之一(除了 React 自己),而且提供了几种不一样的实现方式,用于在各类环境中管理 JavaScript 中的会话历史。react
如下术语咱们会常用:git
browser history
- 针对 DOM 环境,用于支持 HTML5 history API 的浏览器hash history
- 针对 DOM 环境,用于传统的旧式(低版本) 浏览器memory history
- history
在内存上的实现,用于测试以及 React Native 等非 DOM 环境history
对象一般具备如下属性和方法:github
length
- number 历史堆栈中的条目数action
- string 当前的导航操做(push
、replace
或 pop
)location
- object 当前访问的位置信息,可能具备如下属性:web
pathname
- string URL 路径search
- string URL 中的查询字符串hash
- string URL 中的 hash 片断state
- object 存储至 location
中的额外状态数据,仅在 browser history
和 memory history
中有效。push(path, [state])
- function 将一个新条目推入到历史堆栈中replace(path, [state])
- function 替换历史堆栈中的当前条目go(n)
- function 将历史堆栈中的指针移动 n 个条目goBack()
- function 返回到上一个页面,至关于 go(-1)goForward()
- function 进入到下一个页面,至关于 go(1)block(prompt)
- function 阻止导航(请参阅 history 文档)history
对象是可变的。所以建议从 <Route>
渲染组件时接收的属性中直接访问 location
,而不是经过 history.location
进行访问。这样能够保证 React 在生命周期中的钩子函数正常执行。例如:redux
class Comp extends React.Component { componentWillReceiveProps(nextProps) { // locationChanged 会是 true const locationChanged = nextProps.location !== this.props.location; // 错误,locationChanged 永远是 false,由于 history 是可变的。 const locationChanged = nextProps.history.location !== this.props.history.location; } } <Route component={Comp} />
根据你使用的实现方式,还可能存在其它属性。有关详细信息,请参阅 history 文档。api
location
表明应用程序的位置。如当前的位置,将要去的位置,或是以前所在的位置。它看起来像这样:浏览器
{ key: 'ac3df4', // 使用 hash history 时,没有这个属性 pathname: '/somewhere' search: '?some=search-string', hash: '#howdy', state: { [userDefined]: true } }
Router 将在如下几个地方为您提供一个 location
对象:安全
Route component
中,以 this.props.location
方式获取Route render
中,以 ({ location }) => ()
方式获取Route children
中,以 ({ location }) => ()
方式获取withRouter
中,以 this.props.location
方式获取location
对象永远不会发生改变,所以能够在生命周期钩子函数中使用 location
对象来查看当前访问地址是否发生改变。这种技巧在获取远程数据以及使用动画时很是有用。服务器
componentWillReceiveProps(nextProps) { if (nextProps.location !== this.props.location) { // 已经跳转了! } }
能够在如下不一样情境中使用 location
:react-router
一般状况下只是使用一个字符串,可是若是你须要添加一些额外的 state
,以在应用程序跳转到特定位置时可使用,那么你就可使用 location
对象。若是你想根据导航历史而不是路径来组织 UI(如模态对话框),这也颇有用(见模态画廊示例)。
// 一般状况下咱们这么作 <Link to="/somewhere" /> // 可是咱们能够改成使用 location 对象 const location = { pathname: '/somewhere', state: { fromDashboard: true } }; <Link to={location} /> <Redirect to={location} /> history.push(location); history.replace(location);
最终,location
将传递给如下组件:
这将阻止它们在 Router 状态下使用实际位置。这对动画和等待导航很是有用,或者任什么时候候你想诱导一个组件在不一样于真实位置的地方渲染。
一个 match
对象包含有关 <Route path>
如何匹配 URL 的信息。它具备如下属性:
params
- object 根据 path
中指定的动态片断,从 URL 中解析出的键值对isExact
- boolean 若是整个 URL 匹配(不包含尾随字符),则为 true
path
- string 用于匹配的路径模式。可用于构建嵌套的 <Route>
url
- string URL 的匹配部分。可用于构建嵌套的 <Link>
您能够在如下几个地方访问 match
对象:
Route component
中,以 this.props.match
方式获取Route render
中,以 ({ match }) => ()
方式获取Route children
中,以 ({ match }) => ()
方式获取withRouter
中,以 this.props.match
方式获取matchPath
的返回值若是 <Route>
没有定义 path
,并所以始终匹配,则会获得最接近的父匹配。withRouter
也是同样。
在 <Route path="/somewhere" children={({ match }) => ()} />
中,即便 path
与当前位置不匹配,children
指定的内联函数也依然会被调用。这种状况下,match
为 null
。可以在不匹配时依然呈现 <Route>
的内容可能颇有用,可是这样会带来一些挑战。
解析 URL 的默认方式是将 match.url
字符串链接到 relative-path。
`${match.url}/relative-path`
若是你在 match
为 null
时尝试执行此操做,最终会出现 TypeError
错误。这意味着在使用 children
属性时尝试在 <Route>
内部链接 relative-path 是不安全的。
当您在产生空匹配对象的 <Route>
内部使用没有定义 path
的 <Route>
时,会出现相似但更微妙的状况。
// location.pathname = '/matches' <Route path='/does-not-match' children={({ match }) => ( // match === null <Route render={({ match: pathlessMatch }) => ( // pathlessMatch === ??? )} /> )} />
没有 path
的 <Route>
从它的父节点继承 match
对象。若是它的父匹配为 null
,那么它的匹配也将为 null
。这意味着:
path
的 <Route>
,它的父匹配能够为 null
,但它自己须要使用 children
来呈现内容。在正常的渲染周期以外,你可使用和 <Route>
所使用的相同的匹配代码,例如在服务器上呈现以前收集数据依赖关系。
import { matchPath } from 'react-router'; const match = matchPath('/users/123', { path: '/users/:id', exact: true, strict: false });
第一个参数是要匹配的路径名。若是您在服务器上经过 Node.js 使用,它将是 req.path
。
第二个参数是匹配的属性,它们与 <Route>
接受的匹配属性相同:
{ path, // 例如 /users/:id strict, // 可选,默认为 false exact // 可选,默认为false }
你能够经过 withRouter
高阶组件访问 history
对象的属性和最近(UI 结构上靠的最近)的 <Route>
的 match
对象。当组件渲染时,withRouter
会将更新后的 match
、location
和 history
传递给它。
import React from 'react'; import PropTypes from 'prop-types'; import { withRouter } from 'react-router-dom'; // 显示当前位置的 pathname 的简单组件 class ShowTheLocation extends React.Component { static propTypes = { match: PropTypes.object.isRequired, location: PropTypes.object.isRequired, history: PropTypes.object.isRequired } render() { const { match, location, history } = this.props; return ( <div>You are now at {location.pathname}</div> ); } } // 建立一个链接到 Router 的新组件(借用 redux 术语) const ShowTheLocationWithRouter = withRouter(ShowTheLocation)
注意:withRouter 不会订阅位置更改,如 React Redux 的 connect 对状态更改所作的更改。而是在位置更改从 <Router> 组件传播出去以后从新呈现。这意味着除非其父组件从新呈现,不然使用 withRouter 不会在路由转换时从新呈现。若是使用 withRouter 来防止更新被 shouldComponentUpdate 阻塞,那么使用router 包装实现 shouldComponentUpdate 的组件是很是重要的。例如,使用 Redux 时:
// This gets around shouldComponentUpdate withRouter(connect(...)(MyComponent)) // or compose( withRouter, connect(...) )(MyComponent) // This does not connect(...)(withRouter(MyComponent)) // nor compose( connect(...), withRouter )(MyComponent)
有关更多信息,请参阅本指南。
静态方法和属性
封装组件的全部无反应的特定静态方法和属性都会自动复制到 connected 组件。
被包装的组件被公开为返回组件上的静态属性 WrappedComponent
,它可用于隔离测试组件等等。
// MyComponent.js export default withRouter(MyComponent); // MyComponent.test.js import MyComponent from './MyComponent'; render(<MyComponent.WrappedComponent location={{...}} ... />);
一个将做为 ref
属性传递给包装组件的函数。
class Container extends React.Component { componentDidMount() { this.component.doSomething(); } render() { return ( <MyComponent wrappedComponentRef={c => this.component = c} /> ) } }