官方英文文檔 - 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} /> ) } }