react-router簡明學習

前面的話

  路由用來分發請求。後端是提供服務的,因此它的路由是在找controller,前端是顯示頁面的,因此它的路由是在找component。本文將詳細介紹react-router-dom的內容前端

 

Router

  Router是路由器組件的低階接口,一般會使用以下某個高階router來替代它react

<BrowserRouter>
<HashRouter>
<MemoryRouter>
<NativeRouter>
<StaticRouter>

【BrowserRouter】redux

  最經常使用的是BrowserRouter後端

import { BrowserRouter } from 'react-router-dom'

<BrowserRouter
  basename={optionalString}
  forceRefresh={optionalBool}
  getUserConfirmation={optionalFunc}
  keyLength={optionalNumber}
>
  <App/>
</BrowserRouter>

  一、basename: 當前位置的基準 URL。若是頁面部署在服務器的二級(子)目錄,須要將 basename 設置到此子目錄。 正確的 URL 格式是前面有一個前導斜槓,但不能有尾部斜槓瀏覽器

<BrowserRouter basename="/calendar"/>

  二、getUserConfirmation:當導航須要確認時執行的函數。默認使用 window.confirm服務器

// 使用默認的確認函數
const getConfirmation = (message, callback) => {
  const allowTransition = window.confirm(message)
  callback(allowTransition)
}

<BrowserRouter getUserConfirmation={getConfirmation}/>

  三、forceRefresh:當設置爲 true 時,在導航的過程當中整個頁面將會刷新。 只有當瀏覽器不支持 HTML5 的 history API 時,才設置爲 truesession

const supportsHistory = 'pushState' in window.history
<BrowserRouter forceRefresh={!supportsHistory}/>

  四、keyLength:location.key 的長度。默認是 6react-router

<BrowserRouter keyLength={12}/>

  五、BrowserRouter只能渲染單一子元素dom

 

Route

  Route是react-router中最重要的組件,用來匹配請求並渲染相應組件函數

  一、path 路徑的匹配值,能夠包括如下幾種特殊符號

:paramName – 匹配一段位於 /、? 或 # 以後的 URL。 命中的部分將被做爲一個參數
() – 在它內部的內容被認爲是可選的
* – 匹配任意字符(非貪婪的)直到命中下一個字符或者整個 URL 的末尾,並建立一個 splat 參數

  例子以下所示:

<Route path="/hello/:name">         // 匹配 /hello/michael 和 /hello/ryan
<Route path="/hello(/:name)">       // 匹配 /hello, /hello/michael 和 /hello/ryan
<Route path="/files/*.*">           // 匹配 /files/hello.jpg 和 /files/path/to/hello.jpg

  [注意]Route組件不能像普通組件同樣,以屬性的形式傳遞參數,但能夠經過path屬性來傳遞。但必定要區分router後面的:_id或:id

'/category/:_id'

  二、component 要顯示的組件

import { BrowserRouter as Router, Route } from 'react-router-dom'

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

  三、render 函數中return的值就是要顯示的內容

<Route path="/home" render={() => <div>Home</div>}/>

  四、children與render的區別在於,無論有沒有匹配,都想顯示的內容

const ListItemLink = ({ to, ...rest }) => (
  <Route path={to} children={({ match }) => (
    <li className={match ? 'active' : ''}>
      <Link to={to} {...rest}/>
    </li>
  )}/>
)

  [注意]component/render/children只能三個選一個使用

【匹配規則】

  默認地,路由進行寬鬆匹配。在下面例子中,路由匹配到/one時,既顯示組件A,也顯示組件B

<Route  path="/one" component={A}/>
<Route  path="/one/two" component={B}/>

  若是要進行確切匹配,則須要添加exact屬性。這樣,路由匹配到/one時,只顯示組件A

<Route  exact path="/one" component={A}/>
<Route  path="/one/two" component={B}/>

  還有一種是嚴格匹配,即斜槓也必須嚴格匹配。下面例子中,路由匹配到/one/時,會顯示組件A,但匹配到/one時,什麼都不會顯示

<Route  strict path="/one/" component={A}/>

  [注意]嚴格匹配並非確切匹配。下面例子中,路由匹配到/one時,即顯示組件A,也顯示組件B

<Route  strict path="/one" component={A}/>
<Route  path="/one/two" component={B}/>

  若是要確切匹配,則須要

<Route  exact strict path="/one" component={A}/>

  可是,通常地,strict屬性不多使用

【屬性】

  Route默認攜帶三個props:包括match、location、history

  若是使用component,則使用this.props來獲取,若是是render,則在回調函數中使用參數(props)=>{}來獲取

  一、match

  match包括如下屬性

params 鍵值對
isExact 是否確切匹配
path 路徑中設置的值
url URL中的path值

  二、location

  location中包含以下屬性

  [注意]直接訪問location,而不是訪問history.location

{
  key: 'ac3df4', // not with HashHistory!
  pathname: '/somewhere'
  search: '?some=search-string',
  hash: '#howdy',
  state: {
    [userDefined]: true
  }
}

  經過Link傳遞的state,能夠在location中獲取到

  [注意]剛開始時,或者直接刷新瀏覽器,state是沒有值的,只有跳轉到該連接時,state纔有值。再後來,刷新也有值了

  三、history

  history包含以下屬性

length: history棧的長度
action: 當前的action
location: 當前的location對象

  history包含以下方法

push()
goBack() = go(-1)
goForward() = go(1)
go() 跳轉到 history棧中的哪一個enter
replace(path, [state]) 替換history棧中的當前entry
push(path, [state])  添加當前entry到history棧中

 

Redirect

  Redirect將頁面導航到新位置,新位置將覆蓋history棧中的當前位置,相似於服務器端的重定向(HTTP 3xx)

  to屬性能夠是一個字符串,表示跳轉的地址

<Route exact path="/" render={() => (
  loggedIn ? (
    <Redirect to="/dashboard"/>
  ) : (
    <PublicHomePage/>
  )
)}/>

  to屬性也能夠是一個對象

<Redirect to={{
  pathname: '/login',
  search: '?utm=your+face',
  state: { referrer: currentLocation }
}}/>

  push屬性爲true時,表示添加新記錄到history棧中,而不是替換當前記錄

<Redirect push to="/somewhere/else"/>

 

Link

  Link是對a標籤的封裝,提供無刷新的頁面跳轉。Link標籤主要的屬性是to屬性

  一、通常地,to是一個字符串

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

  二、也能夠寫成對象的形式

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

  [注意]在Link裏的子組件或同組件的點擊事件,最好加上阻止默認行爲和阻止冒泡

<Link>
  <div onclick={}></div>
</Link>
<Link onclick={}>

【NavLink】

  NavLink相對於Link來講,增長了一些樣式屬性

  activeClassName表示被匹配的a標籤的樣式名;activeStyle表示被匹配的a標籤的樣式

<NavLink
  to="/faq"
  activeClassName="selected"
>FAQs</NavLink>
<NavLink
  to="/faq"
  activeStyle={{
    fontWeight: 'bold',
    color: 'red'
   }}
>FAQs</NavLink>

  注意: link和history.push都不支持指向外網地址,若是要跳轉到外網,則須要使用window對象下的location對象

   

Switch

  渲染Route或Redirect匹配到的第一個子元素

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

  [注意]switch必須直接包括Route,中間不可包含div,不然不生效

 

跳轉

  若是在實現邏輯跳轉,可以使用以下代碼實現

// utils/history.js
import createBrowserHistory from 'history/createBrowserHistory'
const customHistory = createBrowserHistory()
export default customHistory

  引用以下

import  history  from '@/utils/history'
// 跳轉到首頁
history.push('/')

  要特別注意的是,若是使用utils/history.js,須要使用Router history={history},而不是BrowserRouter

  由於全局只能有一個history實例。 使用import { BrowserRouter as Router } 語句,會自動建立一個history實例的,至關於有兩個實例,則會出現URL發生變化,刷新頁面後,頁面才跳轉的狀況

import { Router, Route, Switch, Redirect } from 'react-router-dom'
import history from '@/utils/history'

<Router history={history}>
  <Switch>
    <Route path="/login" component={Login} />
    <Route path="/" render={props => {if (sessionStorage.getItem('token') && sessionStorage.getItem('user')) {return <Home {...props} />
        }
        return <Redirect to="/login" />
      }} />
  </Switch>
</Router>

【傳參】

  history.push方法也能夠攜帶參數,方法以下

history.push({
  pathname: '/about',
  search: '?the=search',
  state: { some: 'state' }
})

 

 

基礎案例

import React from 'react'
import {
  BrowserRouter as Router,
  Route,
  Link
} from 'react-router-dom'

// 三個基礎呈現組件

const Home = () => (
  <div>
    <h2>Home</h2>
  </div>
)

const About = () => (
  <div>
    <h2>About</h2>
  </div>
)

const Topic = ({ match }) => (
  <div>
    <h3>{match.params.topicId}</h3>
  </div>
)

// 一個內嵌的組件

const Topics = ({ match }) => (
  <div>
    <h2>Topics</h2>
    <ul>
      <li>
        <Link to={`${match.url}/rendering`}>
          Rendering with React
        </Link>
      </li>
      <li>
        <Link to={`${match.url}/components`}>
          Components
        </Link>
      </li>
      <li>
        <Link to={`${match.url}/props-v-state`}>
          Props v. State
        </Link>
      </li>
    </ul>

    <Route path={`${match.url}/:topicId`} component={Topic}/>
    <Route exact path={match.url} render={() => (
      <h3>Please select a topic.</h3>
    )}/>
  </div>
)

// 首頁組件

const BasicExample = () => (
  <Router>
    <div>
      <ul>
        <li><Link to="/">Home</Link></li>
        <li><Link to="/about">About</Link></li>
        <li><Link to="/topics">Topics</Link></li>
      </ul>

      <hr/>

      <Route exact path="/" component={Home}/>
      <Route path="/about" component={About}/>
      <Route path="/topics" component={Topics}/>
    </div>
  </Router>
)
export default BasicExample

 

exact

  exact表示路由須要確切匹配,容易忽略的一點是,它與redux也有着很是密切的關係

  下面的代碼是常見的增刪改查的路由設置

<Switch>
  <Route path="/post/add" component={AddPost} />  
  <Route exact path="/post/:id" component={ShowPost} />        
  <Route path="/post/:id/update" component={UpdatePost} />
  <Route path="/post/:id/delete" component={DeletePost} />
</Switch>

  代碼中,通向showPost的路由設置了exact。通常地,showPost經過fetch獲取了post,並保存到store中的state.post中

  若是此時點擊到updatePost中,能夠經過state.post來獲得值。而若是在updatePost頁面直接刷新的話,則state.post值爲空

  若是要確保頁面刷新後仍然可以取得值,則須要經過route中的location傳值

  可是,這種方法有兩個缺陷。一個是不訪問showPost,而直接訪問UpdatePost不會得到傳遞的值;另外一個是直接在地址欄中更改URL也不會獲取傳遞的值

  二、去掉exact和switch,同時須要更改樣式和路由。使得path="/post/:id/update"時,能夠同時匹配ShowPost和UpdatePost,且UpdatePost的頁面能夠徹底覆蓋ShowPost的頁面

<Route path="/posts/add" component={AddPost} />  
<Route path="/post/:id" component={ShowPost} />        
<Route path="/post/:id/update" component={UpdatePost} />
<Route path="/post/:id/delete" component={DeletePost} />

  可是,因爲這種方法對樣式的定製化需求較高,都須要設置爲定位元素,且根據覆蓋關係來肯定z-index。而且頁面尺寸都須要保持一致。可擴展性不強

相關文章
相關標籤/搜索