React Router v4 入坑指南

萬惡的根源

距離React Router v4 正式發佈也已通過去三個月了,這周把一個React的架子作了升級,以前的路由用的仍是v2.7.0版的,因此決定把路由也升級下,正好「嚐嚐鮮」...react

江湖傳言,目前官方同時維護 2.x 和 4.x 兩個版本。(ヾ(。ꏿ﹏ꏿ)ノ゙咦,此刻相信機智如個人你也會發現,ReactRouter v3 去哪兒了?整丟了??巴拉出鍋了???敢不敢給我個完美的解釋!?)事實上 3.x 版本相比於 2.x 並無引入任何新的特性,只是將 2.x 版本中部分廢棄 API 的 warning 移除掉而已。按照規劃,沒有歷史包袱的新項目想要使用穩定版的 ReactRouter 時,應該使用 ReactRouter 3.x。目前 3.x 版本也還處於 beta 階段,不過會先於 4.x 版本正式發佈。若是你已經在使用 2.x 的版本,那麼升級 3.x 將不會有任何額外的代碼變更。redux

禮貌性簡介下

react router v4.jpg

React Router V4 相較於前面三個版本有根本性變化,首先是遵循Just Component的 API 設計理念,其次API方面也精簡了很多,對新手來講下降了學習難度,但若是是對以前項目的重構,嗯,簡直無**可說。本次升級的主要特色以下:bootstrap

  • 聲明式(Declarative)
  • 可組合 (Composability)

React Router V4 遵循了 React 的理念:萬物皆組件。所以 升級以後的 Route、Link、Switch等都是一個普通的組件。bash

React Router V4 基於 Lerna 管理多個 Repository。在此代碼庫包括:react-router

  • react-router React Router 核心
  • react-router-dom 用於 DOM 綁定的 React Router
  • react-router-native 用於 React Native 的 React Router
  • react-router-redux React Router 和 Redux 的集成
  • react-router-config 靜態路由配置幫助助手

插件初引入

一般咱們在 React 的使用中,通常要引入兩個包,react和 react-dom,那麼react-routerreact-router-dom是否是兩個都要引用呢?注意,前方高能,入門第一坑就在這裏。他們兩個只要引用一個就好了,不一樣之處就是後者比前者多出了<Link> <BrowserRouter>這樣的 DOM 類組件。所以咱們只需引用react-router-dom這個包就OK了。固然,若是搭配redux,你還須要使用react-router-reduxdom

主要組件簡介

在4.0以前版本的 API 中,<Router> 組件的 children 只能是 React Router 提供的各類組件,如<Route>、<IndexRoute>、<Redirect>等。而在 React Router 4 中,你能夠將各類組件及標籤放進 <Router>組件中,他的角色也更像是 Redux 中的 <Provider>。**不一樣的是<Provider>是用來保持與 store 的更新,而<Router>是用來保持與 location 的同步。**示例以下:ide

// 示例1
<Router>
    <div>
      <ul>
        <li><Link to="/">首頁</Link></li>
        <li><Link to="/about">關於</Link></li>
        <li><Link to="/topics">主題列表</Link></li>
      </ul>

      <hr/>

      <Route exact path="/" component={Home}/>
      <Route path="/about" component={About}/>
      <Route path="/topics" component={Topics}/>
    </div>
  </Router>
複製代碼

Router是全部路由組件共用的底層接口,通常咱們的應用並不會使用這個接口,而是使用高級的路由:組件化

  • <BrowserRouter>:使用 HTML5 提供的 history API 來保持 UI 和 URL 的同步;
  • <HashRouter>:使用 URL 的 hash (例如:window.location.hash) 來保持 UI 和 URL 的同步;
  • <MemoryRouter>:能在內存保存你 「URL」 的歷史紀錄(並無對地址欄讀寫);
  • <NativeRouter>:爲使用React Native提供路由支持;
  • <StaticRouter>:從不會改變地址;

TIPS:算是第二坑吧,和以前的Router不同,這裏<Router>組件下只容許存在一個子元素,如存在多個則會報錯。學習

反面典型在這裏:ui

// 示例2
<Router>
      <ul>
        <li><Link to="/">首頁</Link></li>
        <li><Link to="/about">關於</Link></li>
        <li><Link to="/topics">主題列表</Link></li>
      </ul>

      <hr/>

      <Route exact path="/" component={Home}/>
      <Route path="/about" component={About}/>
      <Route path="/topics" component={Topics}/>
  </Router>
複製代碼

沒錯,示例2在沒有<div>爸爸的保護下,會報以下異常信息:

error.jpg

咱們知道,Route組件主要的做用就是當一個location匹配路由的path時,渲染某些UI。示例以下:

<Router>
  <div>
    <Route exact path="/" component={Home}/>
    <Route path="/news" component={NewsFeed}/>
  </div>
</Router>

// 若是應用的地址是/,那麼相應的UI會相似這個樣子:
<div>
  <Home/>
</div>

// 若是應用的地址是/news,那麼相應的UI就會成爲這個樣子:
<div>
  <NewsFeed/>
</div>
複製代碼

<Route>組件有以下屬性:

  • path(string): 路由匹配路徑。(沒有path屬性的Route 老是會 匹配);
  • exact(bool):爲true時,則要求路徑與location.pathname必須徹底匹配;
  • strict(bool):true的時候,有結尾斜線的路徑只能匹配有斜線的location.pathname;

再次奉上兩個鮮活的例子:

exact配置:

路徑 location.pathname exact 是否匹配
/one /one/two true
/one /one/two false

strict配置:

路徑 location.pathname strict 是否匹配
/one/ /one true
/one/ /one/ true
/one/ /one/two true

同時,新版的路由爲<Route>提供了三種渲染內容的方法:

  • <Route component>:在地址匹配的時候React的組件纔會被渲染,route props也會隨着一塊兒被渲染;
  • <Route render>:這種方式對於內聯渲染和包裝組件卻不引發意料以外的從新掛載特別方便;
  • <Route children>:與render屬性的工做方式基本同樣,除了它是無論地址匹配與否都會被調用;

第一種方式沒啥可說的,和以前同樣,這裏咱們重點看下<Route render>的渲染方式:

// 行內渲染示例
<Route path="/home" render={() => <div>Home</div>}/>

// 包裝/合成
const FadingRoute = ({ component: Component, ...rest }) => (
  <Route {...rest} render={props => (
    <FadeIn>
      <Component {...props}/>
    </FadeIn>
  )}/>
)

<FadingRoute path="/cool" component={Something}/>
複製代碼

TIPS: 第三坑! <Route component>的優先級要比<Route render>高,因此不要在同一個<Route>中同時使用這兩個屬性。

和以前版本沒太大區別,重點看下組件屬性:

  • to(string/object):要跳轉的路徑或地址;
  • replace(bool):爲 true 時,點擊連接後將使用新地址替換掉訪問歷史記錄裏面的原地址;爲 false 時,點擊連接後將在原有訪問歷史記錄的基礎上添加一個新的紀錄。默認爲 false

示例以下:

// Link組件示例

// to爲string
<Link to="/about">關於</Link>

// to爲obj
<Link to={{
  pathname: '/courses',
  search: '?sort=name',
  hash: '#the-hash',
  state: { fromDashboard: true }
}}/>

// replace 
<Link to="/courses" replace />
複製代碼

<NavLink><Link> 的一個特定版本, 會在匹配上當前 URL 的時候會給已經渲染的元素添加樣式參數,組件屬性:

  • activeClassName(string):設置選中樣式,默認值爲 active;
  • activeStyle(object):當元素被選中時, 爲此元素添加樣式;
  • exact(bool):爲 true 時, 只有當地址徹底匹配 class 和 style 纔會應用;
  • strict(bool):爲 true 時,在肯定位置是否與當前 URL 匹配時,將考慮位置 pathname 後的斜線;
  • isActive(func):判斷連接是否激活的額外邏輯的功能;

從這裏咱們也能夠看出,新版本的路由在組件化上面確實下了很多功夫,來看看NavLink的使用示例:

// activeClassName選中時樣式爲selected
<NavLink
  to="/faq"
  activeClassName="selected"
>FAQs</NavLink>

// 選中時樣式爲activeStyle的樣式設置
<NavLink
  to="/faq"
  activeStyle={{
    fontWeight: 'bold',
    color: 'red'
   }}
>FAQs</NavLink>

// 當event id爲奇數的時候,激活連接
const oddEvent = (match, location) => {
  if (!match) {
    return false
  }
  const eventID = parseInt(match.params.eventID)
  return !isNaN(eventID) && eventID % 2 === 1
}

<NavLink
  to="/events/123"
  isActive={oddEvent}
>Event 123</NavLink>
複製代碼

該組件用來渲染匹配地址的第一個<Route>或者<Redirect>。那麼它與使用一堆route又有什麼區別呢?

<Switch>的獨特之處是獨它僅僅渲染一個路由。相反地,每個包含匹配地址(location)的<Route>都會被渲染。思考下面的代碼:

<Route path="/about" component={About}/>
<Route path="/:user" component={User}/>
<Route component={NoMatch}/>
複製代碼

若是如今的URL是/about,那麼<About>, <User>, 還有<NoMatch>都會被渲染,由於它們都與路徑(path)匹配。這種設計,容許咱們以多種方式將多個<Route>組合到咱們的應用程序中,例如側欄(sidebars),麪包屑(breadcrumbs),bootstrap tabs等等。 然而,偶爾咱們只想選擇一個<Route>來渲染。若是咱們如今處於/about,咱們也不但願匹配/:user(或者顯示咱們的 「404」 頁面 )。如下是使用 Switch 的方法來實現:

<Switch>
  <Route exact path="/" component={Home}/>
  <Route path="/about" component={About}/>
  <Route path="/:user" component={User}/>
  <Route component={NoMatch}/>
</Switch>
複製代碼

如今,若是咱們處於/about<Switch>將開始尋找匹配的<Route><Route path="/about"/> 將被匹配, <Switch>將中止尋找匹配並渲染<About>。一樣,若是咱們處於/michael<User>將被渲染。

以上就是我對React Router v4 的初試,反正也是一邊查文檔,一邊試水的,若有錯誤或疏漏,還請你們諒解並不吝指正!

相關文章
相關標籤/搜索