React Router 中文文檔(二)

官方英文文檔 - https://reacttraining.com/rea...
版本 - v4.2.0

history

本文檔中的術語 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 當前的導航操做(pushreplacepop
  • location - object 當前訪問的位置信息,可能具備如下屬性:web

    • pathname - string URL 路徑
    • search - string URL 中的查詢字符串
    • hash - string URL 中的 hash 片斷
    • state - object 存儲至 location 中的額外狀態數據,僅在 browser historymemory 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 is mutable

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

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) {
    // 已經跳轉了!
  }
}

能夠在如下不一樣情境中使用 locationreact-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

一個 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 也是同樣。

null matches

<Route path="/somewhere" children={({ match }) => ()} /> 中,即便 path 與當前位置不匹配,children 指定的內聯函數也依然會被調用。這種狀況下,matchnull。可以在不匹配時依然呈現 <Route> 的內容可能頗有用,可是這樣會帶來一些挑戰。

解析 URL 的默認方式是將 match.url 字符串鏈接到 relative-path。

`${match.url}/relative-path`

若是你在 matchnull 時嘗試執行此操做,最終會出現 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 來呈現內容。

matchPath

在正常的渲染週期以外,你可使用和 <Route> 所使用的相同的匹配代碼,例如在服務器上呈現以前收集數據依賴關係。

import { matchPath } from 'react-router';

const match = matchPath('/users/123', {
  path: '/users/:id',
  exact: true,
  strict: false
});

pathname

第一個參數是要匹配的路徑名。若是您在服務器上經過 Node.js 使用,它將是 req.path

props

第二個參數是匹配的屬性,它們與 <Route> 接受的匹配屬性相同:

{
  path, // 例如 /users/:id
  strict, // 可選,默認爲 false
  exact // 可選,默認爲false
}

withRouter

你能夠經過 withRouter 高階組件訪問 history 對象的屬性和最近(UI 結構上靠的最近)的 <Route>match 對象。當組件渲染時,withRouter 會將更新後的 matchlocationhistory 傳遞給它。

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 組件。

Component.WrappedComponent

被包裝的組件被公開爲返回組件上的靜態屬性 WrappedComponent,它可用於隔離測試組件等等。

// MyComponent.js
export default withRouter(MyComponent);

// MyComponent.test.js
import MyComponent from './MyComponent';

render(<MyComponent.WrappedComponent location={{...}} ... />);

wrappedComponentRef: func

一個將做爲 ref 屬性傳遞給包裝組件的函數。

class Container extends React.Component {
  componentDidMount() {
    this.component.doSomething();
  }

  render() {
    return (
      <MyComponent wrappedComponentRef={c => this.component = c} />
    )
  }
}
相關文章
相關標籤/搜索