天天看點

react-router學習總結

基本知識

基本用法

React Router

安裝指令如下:

路由器

Router

就是

React

的一個元件。

import {Router} from 'react-router';
render(
<Router/>, 
document.getElementById('app')
);
           

要注意的是:

Router

元件本身隻是一個容器,真正的路由要通過

Route

元件定義。

import { Router, Route, hashHistory } from 'react-router';

render((
  <Router history={hashHistory}>
    <Route path="/" component={App}/>
  </Router>
), 
document.getElementById('app'));
           

上面代碼: 當通路根路由/(比如http://www.example.com/),元件APP就會加載到

document.getElementById('app')

注意:

Router

元件有一個參數

history

它的值

hashHistory

表示:路由的切換由URL的hash變化決定,即URL的#部分發生變化。

舉例來說:當通路

http://www.example.com/

的時候,實際會看到的是

http://www.example.com/#/

Route

元件定義了URL路徑與元件的對應關系。你可以同時使用多個Route元件:

<Router history={hashHistory}>
  <Route path="/" component={App}/>
  <Route path="/repos" component={Repos}/>
  <Route path="/about" component={About}/>
</Router>
           

上面代碼中:使用者通路/repos(比如http://localhost:8080/#/repos)時,加載Repos元件;通路/about(http://localhost:8080/#/about)時,加載About元件。

嵌套路由

Route元件還可以嵌套:

<Router history={hashHistory}>
  <Route path="/" component={App}>
    <Route path="/repos" component={Repos}/>
    <Route path="/about" component={About}/>
  </Route>
</Router>
           

上面代碼中:使用者通路/repos時,會先加載App元件,然後在它的内部再加載Repos元件。

<App>
  <Repos/>
</App>
           

App元件要寫成下面的樣子:

export default class App extends React.Component{
  render() {
    return (
      <div>
        <h1>React Router Tutorial</h1>
        <ul role="nav">
          <li>
           <Link to="/about" style={{color: 'red'}}>About</Link>
          </li>
          <li>
           <Link to="/repos" style={{color: 'green'}}>Repos</Link>
          </li>
        </ul>
        {this.props.children}
      </div>
    )
  }
}
           

上面代碼中,App元件的

this.props.children

屬性就是子元件。

path 屬性

Route

元件的

path

屬性指定路由的比對規則,這個屬性是可以省略的。如果省略,不管路徑是否比對,總是會加載指定元件。

<Route path="inbox" component={Inbox}>
   <Route path="messages/:id" component={Message} />
</Route>
           

上面代碼中,當使用者通路

/inbox/messages/:id

時,會加載下面的元件。

<Inbox>
  <Message/>
</Inbox>
           

如果省略外層Route的path參數,寫成下面的樣子。

<Route component={Inbox}>
  <Route path="inbox/messages/:id" component={Message} />
</Route>
           

現在使用者通路

/inbox/messages/:id

時,元件加載還是原來的樣子。

<Inbox>
  <Message/>
</Inbox>
           

通配符

path屬性可以使用通配符。

<Route path="/hello/:name">
// 比對 /hello/michael
// 比對 /hello/ryan

<Route path="/hello(/:name)">
// 比對 /hello
// 比對 /hello/michael
// 比對 /hello/ryan

<Route path="/files/*.*">
// 比對 /files/hello.jpg
// 比對 /files/hello.html

<Route path="/files/*">
// 比對 /files/ 
// 比對 /files/a
// 比對 /files/a/b

<Route path="/**/*.jpg">
// 比對 /files/hello.jpg
// 比對 /files/path/to/file.jpg
           

通配符的規則如下:

  1. :paramName

    :paramName比對URL的一個部分,直到遇到下一個/、?、#為止。這個路徑參數可以通過this.props.params.paramName取出。

  2. ()

    ()表示URL的這個部分是可選的。

  3. *

    *比對任意字元,直到模式裡面的下一個字元為止。比對方式是非貪婪模式。

  4. **

    ** 比對任意字元,直到下一個/、?、#為止。比對方式是貪婪模式。

path屬性也可以使用相對路徑(不以/開頭),比對時就會相對于父元件的路徑。嵌套路由如果想擺脫這個規則,可以使用絕對路由。

特别注意: 路由比對規則是從上到下執行,一旦發現比對,就不再其餘的規則了。

<Route path="/comments" ... />
<Route path="/comments" ... />
           

上面代碼中,路徑

/comments

同時比對兩個規則,第二個規則不會生效。

設定路徑參數時,需要特别小心這一點。

<Router>
  <Route path="/:userName/:id" component={UserPage}/>
  <Route path="/about/me" component={About}/>
</Router>
           

上面代碼中,使用者通路

/about/me

時,不會觸發第二個路由規則,因為它會比對

/:userName/:id

這個規則。是以,帶參數的路徑一般要寫在路由規則的底部。

對于

URL

的查詢字元串

/foo?bar=baz

,可以用

this.props.location.query.bar

擷取。

Link标簽

Link

元件用于取代

<a>

元素,生成一個連結,允許使用者點選後跳轉到另一個路由。它基本上就是

<a>

元素的React 版本,可以接收

Router

的狀态。

render() {
  return <div>
    <ul role="nav">
      <li><Link to="/about">About</Link></li>
      <li><Link to="/repos">Repos</Link></li>
    </ul>
  </div>
}
           

特别注意:Link 元件中的to屬性定義了 URL 中 #号 之後的路徑參數,是以要和 Route 元件中的 path值相對應。

注意: 在Router元件之外,導航到路由頁面,可以使用浏覽器的History API,像下面這樣寫:

import { browserHistory } from 'react-router';
browserHistory.push('/some/path');
           

IndexRoute 元件

看下面的例子更好了解:

<Router history={browserHistory}>
        <Route path="/" component={App}>
            <Route path="/repos" component={Repos}/>
            <Route path="/about" component={About}/>
        </Route>
    </Router>
           

對于上面的代碼,如果我們通路根路徑/,不會加載任何子元件。App元件的

this.props.children

null

IndexRoute

就是用來顯式指定根路由的子元件,即指定預設情況下加載的子元件。你可以把IndexRoute想象成某個路徑的index.html。

<Router history={browserHistory}>
        <Route path="/" component={App}>
            <IndexRoute component={Home}/>
            <Route path="/repos" component={Repos}/>
            <Route path="/about" component={About}/>
        </Route>
    </Router>
           

現在,使用者通路/的時候,加載的元件結構如下:

<App>
  <Home/>
</App>
           

這種元件結構就很清晰了:App隻包含下級元件的共有元素,本身的展示内容則由Home元件定義。這樣有利于代碼分離,也有利于使用React Router提供的各種API。

特别注意:

IndexRoute

元件沒有路徑參數

path

Redirect 元件

<Redirect>

元件用于路由的跳轉,即使用者通路一個路由,會自動跳轉到另一個路由。

<Route path="inbox" component={Inbox}>
  {/* 從 /inbox/messages/:id 跳轉到 /messages/:id */}
  <Redirect from="messages/:id" to="/messages/:id" />
</Route>
           

現在通路

/inbox/messages/5

,會自動跳轉到

/messages/5

IndexRedirect 元件

IndexRedirect

元件用于通路根路由的時候,将使用者重定向到某個子元件。

<Route path="/" component={App}>
  <IndexRedirect to="/welcome" />
  <Route path="welcome" component={Welcome} />
  <Route path="about" component={About} />
</Route>
           

上面代碼中,使用者通路根路徑時,将自動重定向到子元件

welcome

IndexLink

如果連結到根路由/,不要使用Link元件,而要使用

IndexLink

元件。

這是因為對于根路由來說,

activeStyle和activeClassName

會失效。或者說總是生效,因為/會比對任何子路由。而IndexLink元件會使用路徑的精确比對。

<IndexLink to="/" activeClassName="active">
  Home
</IndexLink>
           

上面代碼中,根路由隻會在精确比對時,才具有

activeClassName

另一種方法是使用Link元件的

onlyActiveOnIndex

屬性,也能達到同樣效果。

<Link to="/" activeClassName="active" onlyActiveOnIndex={true}>
  Home
</Link>
           

實際上,

IndexLink

就是對Link元件的

onlyActiveOnIndex

屬性的包裝。

histroy 屬性

Router

元件的

history

屬性,用來監聽浏覽器位址欄的變化,并将URL解析成一個位址對象,供

React Router

比對。

history屬性,一共可以設定三種值:

  • browserHistory

    如果設為

    browserHistory

    ,浏覽器的路由就不再通過Hash完成了,而顯示正常的路徑

    example.com/some/path

    ,背後調用的是浏覽器的

    History API

    但是,這種情況需要對

    伺服器改造

    。否則使用者直接向伺服器請求某個子路由,會顯示網頁找不到的404錯誤。

    如果開發伺服器使用的是

    webpack-dev-server,加上--history-api-fallback

    參數就可以了。
  • hashHistory

    如果設為hashHistory,路由将通過URL的hash部分(#)切換,URL的形式類似

    example.com/#/some/path

  • createMemoryHistory

    createMemoryHistory

    主要用于伺服器渲染。它建立一個記憶體中的history對象,不與浏覽器URL互動。

react-router 是基于 history 子產品提供的 api 進行開發的。

假如我們有一台提供 Web 服務的伺服器的網絡位址是:10.0.0.1,而該 Web 服務又提供了三個可供使用者通路的頁面,其頁面 URI 分别是:

http://10.0.0.1/
http://10.0.0.1/about
http://10.0.0.1/concat
           

那麼其路徑就分别是 /,/about,/concat。

當使用者使用 http://10.0.0.1/about 來通路該頁面時,Web 服務會接收到這個請求,然後會解析 URI 中的路徑 /about,在 Web 服務的程式中,該路徑對應着相應的處理邏輯,程式會把請求交給路徑所對應的處理邏輯,這樣就完成了一次「路由分發」,這個分發就是通過「路由」來完成的。

參考博文:

React Router 使用教程

前端路由實作與 react-router 源碼分析