中文 React Router

React/Router

文檔已廢棄,關閉更新,詳情請往 這裏:

React Router 一個針對React而設計的路由解決方案、能夠友好的幫你解決React components 到URl之間的同步映射關係。javascript

概覽

在闡明React Router能夠幫你解決的問題以前咱們來舉一個沒有引用React Router 的簡單例子。html

沒使用 React Routerjava

var About = React.createClass({
  render: function () {
    return <h2>About</h2>;
  }
});

var Inbox = React.createClass({
  render: function () {
    return <h2>Inbox</h2>;
  }
});

var Home = React.createClass({
  render: function () {
    return <h2>Home</h2>;
  }
});

var App = React.createClass({
  render () {
    var Child;
    switch (this.props.route) {
      case 'about': Child = About; break;
      case 'inbox': Child = Inbox; break;
      default:      Child = Home;
    }

    return (
      <div>
        <h1>App</h1>
        <Child/>
      </div>
    )
  }
});

function render () {
  var route = window.location.hash.substr(1);
  React.render(<App route={route} />, document.body);
}

window.addEventListener('hashchange', render);
render(); // render initially

在hash值改變的時候,App 將會根據this.props.route 值的改變來動態渲染 <Child/> component。
這樣子的作法看起來很直接,可是這也會讓整個應用程序變得更加複雜。
咱們能夠想一想,若是組件 Inbox 有一些內嵌的子組件須要根據 例如 inbox/message/:id 或者 inbox/unread 等這樣的路由規則作動態渲染的時候。咱們須要一些更加智能的手段來把路由信息傳遞給咱們的App,這樣Inbox 組件能夠根據URL的映射關係來控制哪些子組件應該須要被渲染。咱們的不少組件應該根據URL的規則來作動態渲染。在不使用路由規則的前提下,複雜一點的路由需求就須要咱們寫不少條件判斷的代碼去去解決實RL和層級組件的同步問題。react

引入路由git

解決複雜的URL和層級組件之間的映射關係式React Router 的核心。咱們使用聲明式的方式爲咱們舉的例子引入路由。咱們使用JSX的方式來進行路由的配置,這樣咱們能夠經過屬性的方式來配置頁面視圖的層級關係。
先來看看路由的配置github

var Router = require('react-router');
var Route = Router.Route;

// declare our routes and their hierarchy
var routes = (
  <Route handler={App}>
    <Route path="about" handler={About}/>
    <Route path="inbox" handler={Inbox}/>
  </Route>
);

咱們刪除掉一些在組件內判斷路由邏輯的代碼。而後用<RouteHandle/> 替換 <Child/>.而後代碼變成下面這個樣子。數組

var RouteHandler = Router.RouteHandler;

var App = React.createClass({
  render () {
    return (
      <div>
        <h1>App</h1>
        <RouteHandler/>
      </div>
    )
  }
});

最後咱們須要監聽url的變化來動態渲染應用,加入下面的代碼。promise

Router.run(routes, Router.HashLocation, (Root) => {
  React.render(<Root/>, document.body);
});

Root 是 React Router 路由匹配後決定渲染的最高層級的組件,告訴 RouterHandle 應該渲染的內容是什麼。
<Router/> 組件是不會被渲染的。只是一個建立內部路由規則的配置對象。服務器

接下來咱們爲應用添加更多的UI組件
如今咱們計劃給Inbox UI 添加Inbox message 子組件。首先咱們須要添加一個新的Message組件。而後咱們在原有的inbox路由下面爲 Message 組件添加新的路由,這樣就能夠獲得嵌套的UI。react-router

var Message = React.createClass({
  render () {
    return <h3>Message</h3>;
  }
});

var routes = (
  <Route handler={App}>
    <Route path="about" handler={About}/>
    <Route path="inbox" handler={Inbox}>
      <Route path="messages/:id" handler={Message}/>
    </Route>
  </Route>
);

如今咱們訪問 inbox/message/jKei3c32c的URL就能夠匹配到新的路由規則並能夠匹配到App->Inbox->Message 這個分支下的UI。

獲取url的參數
咱們須要獲取到一些Url的信息,這樣咱們能夠根據這些參數從服務器端獲取數據。咱們把交給<Route/>匹配好的組件稱爲RouterHandler. RouterHandler 實例能夠獲取到一些很是有用的屬性當你渲染組件的時候。特別是一些從URL動態獲取的參數信息。好比在咱們舉例中得 :id

var Message = React.createClass({
  componentDidMount: function () {
    // from the path `/inbox/messages/:id`
    var id = this.props.params.id;
    fetchMessage(id, function (err, message) {
      this.setState({ message: message });
    })
  },
  // ...
});

嵌套的UI和多層級的URLs是 不須要耦合的。
有了React Router,咱們不須要用嵌套UI的方式來對應多層級的URL。反過來,獲取嵌套組件的UI,咱們也不須要有多層級的URL與它對應。

好比說咱們有/about/company 這樣的URL,咱們不須要嵌套UI組件到About組件中。

var routes = (
  <Route handler={App}>
    <Route path="about" handler={About}/>
    <Route path="about/company" handler={Company}/>
  </Route>
);

雖說咱們的URL是有層級嵌套的,可是咱們UI組件中得 About 組件和 Company 組件卻能夠是相鄰展平在同級目錄的。

如今讓咱們往路由中添加url /archive/messages/:id 而後讓該路由嵌套到inbox UI裏面,即便 這個URL不跟上層 Router 的URL 嵌套。咱們須要作三件事讓匹配下面規則的路由正常工做。

一、url 要以 / 這樣的絕對路徑開頭,這表明不會從父路由繼承路由規則。
二、嵌套在Inbox route 中的router 會致使UI組件的層級嵌套。
三、肯定你已經有必需的動態URL片斷,在這裏咱們只有 :id ,因此處理起來至關簡單。

var routes = (
  <Route handler={App}>
    <Route path="inbox" handler={Inbox}>
      <Route path="messages/:id" handler={Message}/>
      <Route path="/archive/messages/:id" handler={Message}/>
    </Route>
  </Route>
);

這就是React Router的核心,應用的UI組件是層層嵌套的。如今咱們可讓這些嵌套的UI組件和URL規則保持同步了。

Route 配置

DefaultRoute

一個RefaultRoute 是一個已匹配父組件會默認展現的子組件。
你指望在沒有子組件被匹配的時候一個子RouterHandler老是可以渲染到頁面。

Props
handle
RouterHandler 是你須要渲染到頁面的匹配規則的組件
name (可選)
當你使用linking 和 transitioning 的路由名字

舉例

<Route path="/" handler={App}>

  <!--
    When the url is `/`, this route will be active. In other
    words, `Home` will be the `<RouteHandler/>` in `App`.
  -->
  <DefaultRoute handler={Home}/>

  <Route name="about" handler={About}/>
  <Route name="users" handler={Users}>
    <Route name="user" handler={User} path="/user/:id"/>

    <!-- when the url is `/users`, this will be active -->
    <DefaultRoute name="users-index" handler={UsersIndex}/>

  </Route>
</Route>

NotFoundRoute

NotFoundRoute 會在父組件匹配成功但沒有一個同級組件被匹配的時候會被激活。
你可使用它來處理不合法的連接。

提示
NotFoundRoute不是針對當資源沒有被找到而設計的。路由沒有匹配到特定的URL和經過一個合法的URL沒有查找到資源是有卻別的。url course/123 是一個合法的url並可以匹配到對應的路由,因此它是找到了的意思。可是經過123 去匹配資源的時候卻沒有找到,這個時候咱們並不像跳轉到一個新的路由,咱們能夠設置不一樣的狀態來選軟不一樣的UI組件,而不是經過NotFoundRoute 來解決。

props

handler
RouterHandler 是你須要渲染到頁面的匹配規則的組件

舉例

<Route path="/" handler={App}>
  <Route name="course" path="course/:courseId" handler={Course}>
    <Route name="course-dashboard" path="dashboard" handler={Dashboard}/>

    <!-- ie: `/course/123/foo` -->
    <NotFoundRoute handler={CourseRouteNotFound} />
  </Route>

  <!-- ie: `/flkjasdf` -->
  <NotFoundRoute handler={NotFound} />
</Route>

最後一個 NotFoundRoute 將會渲染到 APP 內。 第一個將會被渲染到Course 內。

Redirect

Recirect 能夠跳轉到另一個路由中。

props

from
你想開始redirect的地址,包括一些動態的地址。默認爲* ,這樣任何匹配不到路由規則的狀況多回被重定向到另一個地方。
to
你想要重定向到得路由名字。
params
默認狀況下,這些參數將會自動傳遞到新的路由,你也能夠指定他們,特別是你不須要的時候。
query
params同樣

舉例

<!--
  lets say we want to change from `/profile/123` to `/about/123`
  and redirect `/get-in-touch` to `/contact`
-->
<Route handler={App}>
  <Route name="contact" handler={Contact}/>
  <Route name="about-user" path="about/:userId" handler={UserProfile}/>
  <Route name="course" path="course/:courseId">
    <Route name="course-dashboard" path="dashboard" handler={Dashboard}/>
    <Route name="course-assignments" path="assignments" handler={Assignments}/>
  </Route>

  <!-- `/get-in-touch` -> `/contact` -->
  <Redirect from="get-in-touch" to="contact" />

  <!-- `/profile/123` -> `/about/123` -->
  <Redirect from="profile/:userId" to="about-user" />

  <!-- `/profile/me` -> `/about-user/123` -->
  <Redirect from="profile/me" to="about-user" params={{userId: SESSION.USER_ID}} />
</Route>

<Redirect> 可以被放置到路由的任何層級。若是你選擇把它放在路由某一層級的下方,那麼from路徑也會匹配到它上層的路徑。

Route

Route 用於聲明式地映射路由規則到你多層嵌套的應用組件。
props
name(可選)
name 在路由中是惟一的,被使用在 Link 組件和路由轉換的方法中。
path(optional)
在url中使用的路徑,若是不填寫的話,路徑就是name,若是name也沒有的話,默認就是 /.
handler
當路由被匹配的時候會被 RouteHander 渲染的組件。
children
路由是能夠嵌套的,若是子路由的路徑被匹配,那麼父路由也處於激活狀態。

ignoreScrollBehavior
當路由或者路由的params 改變的時候,路由會根據scrollBehavior 來調整頁面滾動條的位置。可是 你也能夠不選擇這項功能,特別是在一些搜索頁面或者是 tab切換的頁面。

Top-Level

Router.create

建立一個新的路由。

Signature
Router.create(options)

Options
routes

location

scrollBehavior

onAbort
Used server-side to know when a route was redirected.

Method
run(callback)
啓動路由,和Router.run 同樣

舉例

// the more common API is
Router.run(routes, Router.HistoryLocation, callback);

// which is just a shortcut for
var router = Router.create({
  routes: routes,
  location: Router.HistoryLocation
});

router.run(callback);

Router.run

The main API into react router. It runs your routes, matching them against a location, and then calls back with the next state for you to render.

signature

Router.run(routes,[location,],callback)
參數
routes
location (可選)
默認值是Router.HashLocation 若是你設置了Location 那麼它的改變會被監聽。若是你設置了一個字符路勁,那麼路由會當即匹配並執行回調函數。

舉例

// Defaults to `Router.HashLocation`
// callback is called whenever the hash changes
Router.run(routes, callback);

// HTML5 History
// callback is called when history events happen
Router.run(routes, Router.HistoryLocation, callback);

// Server rendering
// callback is called once, immediately.
Router.run(routes, '/some/path', callback);

callback(Root,state)
回調函數接收兩個參數
一、 Root
二、 state

Root
是一個包含了全部匹配組件的一個組件,它用來渲染你的組件。
state
一個包含了匹配狀態的對象。
state.path
帶有查詢參數的當前URL
state.action
一個觸發路由改變的操做
state.pathname
不帶查詢參數的URL
state.params
當前被激活路由匹配路徑對應的參數 如 /:id 對應的id值.

state.query
當前被激活路由匹配路徑對應的查詢參數
state.routes
包含了匹配路由的數組,在組件渲染以前獲取數據會顯得頗有幫助。
能夠查看 example async-data

舉例

基本用法

javascript
Router.run(routes, function (Root) {
// whenever the url changes, this callback is called again
React.render(<Root/>, document.body);
});

var resolveHash = require('when/keys').all;

var SampleHandler = React.createClass({
statics: {

// this is going to be called in the `run` callback
fetchData: function (params) {
  return fetchStuff(params);
}

},
// ...
});

Router.run(routes, Router.HistoryLocation, function (Root, state) {

// create the promises hash
var promises = state.routes.filter(function (route) {

// gather up the handlers that have a static `fetchData` method
return route.handler.fetchData;

}).reduce(function (promises, route) {

// reduce to a hash of `key:promise`
promises[route.name] = route.handler.fetchData(state.params);
return promises;

}, {});

resolveHash(promises).then(function (data) {

// wait until we have data to render, the old screen stays up until
// we render
React.render(<Root data={data}/>, document.body);

});
});

something.serve(function (req, res) {
Router.run(routes, req.path, function (Root, state) {

// could fetch data like in the previous example
fetchData(state.matches).then(function (data) {
  var html = React.renderToString(<Root data={data} />);
  res.send(html);
});

});
});

#Components

##Link
用於在應用程序中導航的一種主要方式。``Link``將會渲染出標籤屬性href 變得容易被理解。
當``Link``定位的路由被激活的時候自動 顯示爲 定義的 ``activeClassName`` 和/或者
``activeStyle`` 定義的樣式。

**Props**
``to``
要被定位到的路由名字,或者是完整的路徑

``params``

包含了名字/值的對象,和路由地址的動態段對應一致。

``query``

一個包含名字/值 的對象,它會成爲地址中的查詢參數

**舉例**

// given a route config like this
<Route name="user" path="/users/:userId"/>

// create a link with this
<Link to="user" params={{userId: "123"}}/>

// though, if your user properties match up to the dynamic segements:
<Link to="user" params={user}/>

``query``

一個包裝成javascript對象的字符串查詢參數

``activeClassName``

當路由被激活是 ``Link`` 接收的 className,默認值爲 ``active``

``activeStyle ``

當路由被激活是連接元素 展現的style樣式。

``onClick``

對點擊時間的常規處理,僅僅在標籤``<a>`` 上起效。調用 ``e.preventDefault`` 或者是返回false 將會阻止阻止事件發射。經過 ``e.stopPropagation()`` 將會阻止時間冒泡。

**others**

你也能夠在<a>上傳遞 props,例如 title,id , className 等。

**舉例**

提供一個形式像 ``<Router name="user" path="/user/:userid" />:`` 這樣的路由

<Link to="user" params={{userId: user.id}} query={{foo: bar}}>{user.name}</Link>
<!-- becomes one of these depending on your router and if the route is
active -->
Michael
Michael

<!-- or if you have the full url already, you can just pass that in -->
<Link to="/users/123?foo=bar">{user.name}</Link>

<!-- change the activeClassName -->
<Link activeClassName="current" to="user" params={{userId: user.id}}>{user.name}</Link>

<!-- change style when link is active -->
<Link style={{color: 'white'}} activeStyle={{color: 'red'}} to="user" params={{userId: user.id}} query={{foo: bar}}>{user.name}</Link>

##Root
React router 建立的應用頂層組件。

**舉例**

Router.run(routes, (Root) => {
React.render(<Root/>, document.body);
});

**說明**
當前路由的實例和 ``Root`` 一致。

var MyRouter = Router.create({ routes });

MyRouter.run((Root) => {
Root === MyRouter; // true
});

當前這僅僅是一個實現的細節,咱們會逐步將它設計成一個公共的API。


##Route Handler
用戶定義的一個組件,做爲傳遞給``Routes`` 的一個 ``handler`` 屬性。 路由會在你經過 ``RouterHandler`` 渲染組件的時候給你注入一些屬性值。同時在路由轉換的時候調用一些生命週期的靜態方法。

**注入的屬性**

``params``

url 中的動態段。

``query``

url中的查詢參數

``path``

完整的url 路勁

**舉例**

// given a route like this:
<Route path="/course/:courseId/students" handler={Students}/>

// and a url like this:
"/course/123/students?sort=name"

var Students = React.createClass({
render () {

this.props.params.courseId; // "123"
this.props.query.sort; // "name"
this.props.path; // "/course/123/students?sort=name"
// ...

}
});

**靜態的生命週期方法**

你能夠定義一些在路由轉換時會調用的靜態方法到你的路由handler 對應的組件中。

``willTransitionTo(transition,params,query,callback)``

當一個handler 將要被渲染的時候被調用。爲你提供了中斷或者是重定向的機會。你能夠在異步調用的時候暫停轉換,在完成以後能夠調用``callback(error)``  方法。或者在參數列表中省略callback。

``willTranstionFrom(transition,component,callback)``

當一個被激活路由將要跳出的時候給你提供了中斷跳出的方法。``component`` 是當前的組件。你可能須要檢查一下 state 的狀態來決定是否須要跳出。

**關於 ``callback`` 的參數**

 若是你在參數列表中添加了callback,你須要在最後的時候調用它,即便你使用的是重定向。

**舉例**

var Settings = React.createClass({
statics: {

willTransitionTo: function (transition, params, query, callback) {
  auth.isLoggedIn((isLoggedIn) => {
    transition.abort();
    callback();
  });
},

willTransitionFrom: function (transition, component) {
  if (component.formHasUnsavedData()) {
    if (!confirm('You have unsaved information,'+
                 'are you sure you want to leave this page?')) {
      transition.abort();
    }
  }
}

}

//...});

相關文章
相關標籤/搜索