每日一學:React-router ? V4

在 react-router-dom 的官方教程中,一共給出12個示例,但是個人認爲,着12個示例看着真的很累人,很多寫法,不是標準的企業項目應用的寫法,所以針對這個現狀,我想用企業項目開發的要求,對教程中的每一個示例進行重寫,這篇教程就是它的第一個示例——基本使用和介紹。

HashRouter還是BrowserRouter

<font color=#ff502c>react-router</font> 的工作方式,是在組件樹頂層放一個Router組件,然後在組件樹中散落着很多reactr
組件,頂層的Router組件負責分析監聽URL的變化,在它保護傘之下的Route組件可以直接讀取這些信息。

很明顯,Router和Route的配合,就是之前我們介紹過的"提供者模式",Router是
<font color=#ff502c>"提供者"</font>
,Route是 <font color=#ff502c>"消費者"</font>。

Router其實也是一層抽象,讓下面的Route無需各種不同URL設計的細節,不要以爲
URL就一種設計方法,至少可以分爲兩種。

第一種:比如 / 對應 <font color=#ff502c>Home</font> 頁, /about對應<font color=#ff502c>about</font> 頁,但是這樣的設計需要服務器端渲染,
應爲用戶可以直接訪問任何一個URL,服務器必須能對 / 的訪問返回HTML, 也要對 /about 的訪問返回HTML。

第二種:只有一個路徑 / ,通過URL後面的 <font color=#ff502c>#</font> 部分來決定路由, <font color=#ff502c>/#/</font> 對應Home頁。
<font color=#ff502c>/#/about</font>
對應About頁。應爲URL種 # 之後的部分是不會發送給服務器的,所以,
無論哪個URL,最後都是訪問服務器的 / 路徑,服務器也只需要返回同一份HTNL就可以,然後由瀏覽器端解析 # 後的部分
,完成瀏覽器端渲染。

組件

<BrowserRouter>

一個使用了 HTML5 history API 的高階路由組件,保證你的 UI 界面和 URL 保持同步。此組件擁有以下屬性:

  1. <font color=#ff502c>basename: string </font>

爲所有位置添加一個基準URL.
使用場景:假如你需要把頁面部署到服務器的二級目錄,你可以使用 basename 設置到此目錄。

<BrowserRouter basename="/wsm" />
<Link to="/react" /> // 最終渲染爲 <a href="/minooo/react">
  1. <font color=#ff502c>getUserConfirmation: func </font>

導航到此頁面前執行的函數,默認使用 window.confirm
使用場景:當需要用戶進入頁面前執行什麼操作時可用,不過一般用到的不多。

const getConfirmation = (message, callback) => {
  const allowTransition = window.confirm(message)
  callback(allowTransition)
}
<BrowserRouter getUserConfirmation={getConfirmation('Are you sure?', yourCallBack)} />
  1. <font color=#ff502c>forceRefresh: bool </font>

作用:當瀏覽器不支持 HTML5 的 history API 時強制刷新頁面。
使用場景:同上。

const supportsHistory = 'pushState' in window.history
<BrowserRouter forceRefresh={!supportsHistory} />
  1. <font color=#ff502c>keyLength: number </font>

作用:設置它裏面路由的 location.key 的長度。默認是6。(key的作用:點擊同一個鏈接時,每次該路由下的 location.key都會改變,可以通過 key 的變化來刷新頁面。)
使用場景:按需設置。

<BrowserRouter keyLength={12} />

最後展示實例:

<BrowserRouter
  basename="/minooo"
  forceRefresh={false}
  getUserConfirmation={getConfirmation()}
  keyLength={12}
></BrowserRouter>

<Route>

<Route> 自帶三個 render method 和三個 props 。
render methods 分別是:

  1. <font color=#ff502c>Route component</font>
  2. <font color=#ff502c>Route render </font>
  3. <font color=#ff502c>Route children </font>

props 分別是:

  • <font color=#ff502c> match</font>
  • <font color=#ff502c>location</font>
  • <font color=#ff502c>history</font>

所有的 render method 無一例外都將被傳入這些 props。

component

只有當訪問地址和路由匹配時,一個 React component 纔會被渲染,此時此組件接受 route props (match, location, history)。

當使用component時,router將使用React.createElement根據給定的Component創建
一個新的React元素。這意味着如果你使用內聯函數傳值給component將會產生不必要的重複裝載。對於內聯渲染(inline rendering), 建議使用 render prop。

<Route path="/user/:username" component={User} />
const User = ({ match }) => {
  return <h1>Hello {match.params.username}!</h1>
}

<Link>

<font color=#ff502c> to: string</font>
作用:跳轉到指定路徑
使用場景:如果只是單純的跳轉就直接用字符串形式的路徑。

<Link to="/courses" />

<font color=#ff502c> to: object</font>
作用:攜帶參數跳轉到指定路徑
作用場景:比如你點擊的這個鏈接將要跳轉的頁面需要展示此鏈接對應的內容,又比如這是個支付跳轉,需要把商品的價格等信息傳遞過去。

<Link to={{
  pathname: '/course',
  search: '?sort=name',
  state: { price: 18 }
}} />

<NavLink>

這是 <Link> 的特殊版,顧名思義這就是爲頁面導航準備的。因爲導航需要有 “激活狀態”。

<font color=#ff502c>activeClassName: string</font>
導航選中激活時候應用的樣式名,默認樣式名爲 active

<NavLink
  to="/about"
  activeClassName="selected"
>MyBlog</NavLink>

<Switch>

只渲染出第一個與當前訪問地址匹配的 <Route> 或 <Redirect>。

Prompt

當用戶離開當前頁面前做出一些提示。

  • <font color=#ff502c> message: string</font>

當用戶離開當前頁面時,設置的提示信息。

<Prompt message="確定要離開?" />
  • <font color=#ff502c>message: func</font>

當用戶離開當前頁面時,設置的回掉函數

<Prompt message={location => (
  `Are you sue you want to go to ${location.pathname}?` 
)} />
  • <font color=#ff502c> when: bool</font>

通過設置一定條件要決定是否啓用 Prompt

<Prompt 
  when={this.state.dirty} 
  message="數據尚未保存,確定離開?" />

對象和方法

match

match 對象包含了 <Route path> 如何與 URL 匹配的信息,具有以下屬性:

  • <font color=#ff502c>params: object</font> 路徑參數,通過解析 URL 中的動態部分獲得鍵值對
  • <font color=#ff502c>isExact: bool</font> 爲 true 時,整個 URL 都需要匹配
  • <font color=#ff502c>path: string</font> 用來匹配的路徑模式,用於創建嵌套的 <Route>
  • <font color=#ff502c>url: string URL</font> 匹配的部分,用於嵌套的 <Link>

在以下情境中可以獲取 match 對象

  • 在<font color=#ff502c>Route component</font> 中,以 this.props.match獲取
  • 在 <font color=#ff502c>Route render</font> 中,以 ({match}) => () 方式獲取
  • 在 <font color=#ff502c>Route children </font> 中,以 ({match}) => () 方式獲取
  • 在 <font color=#ff502c>withRouter</font> 中,以 this.props.match的方式獲取
  • <font color=#ff502c>matchPath</font> 的返回值

location

location 是指你當前的位置,將要去的位置,或是之前所在的位置

在以下情境中可以獲取 location 對象

  • 在<font color=#ff502c> Route component </font> 中,以 this.props.location 獲取
  • 在 <font color=#ff502c>Route render</font> 中,以 ({location}) => () 方式獲取
  • 在 <font color=#ff502c>Route children </font> 中,以 ({location}) => () 方式獲取
  • 在 <font color=#ff502c>withRouter</font> 中,以 this.props.location 的方式獲取

location 對象不會發生改變,因此可以在生命週期的回調函數中使用 location 對象來查看當前頁面的訪問地址是否發生改變。這種技巧在獲取遠程數據以及使用動畫時非常有用

componentWillReceiveProps(nextProps) {
  if (nextProps.location !== this.props.location) {
    // 已經跳轉了!
  }
}

可以在不同情境中使用 location:

  1. Link to={location} />
  2. NaviveLink to={location} />
  3. Redirect to={location />
  4. history.push(location)
  5. history.replace(location)

history

history 對象是可變的,因爲建議從 <Route> 的 prop 裏來獲取 location,而不是從 history.location 直接獲取。這樣可以保證 React 在生命週期中的鉤子函數正常執行,例如以下代碼:

class Comp extends React.Component {
  componentWillReceiveProps(nextProps) {
    // locationChanged
    const locationChanged = nextProps.location !== this.props.location

    // 錯誤方式,locationChanged 永遠爲 false,因爲history 是可變的
    const locationChanged = nextProps.history.location !== this.props.history.location
  }
}

最後實現的一個簡單完整的react-router

import React, { Component } from 'react';
import './App.css';
import {
  BrowserRouter as Router,
  Link,
  Route,
  Switch,
} from 'react-router-dom';
import Home from './components/Home/Home'
class App extends Component {
  render() {
    const About = ( ) => <h1>About</h1>;
    const Nested = () => (
      <div>
        <Link to="/nested/one">One</Link>
        <Link to="/nested/two">Two</Link>
        <Link replace to="/nested/Three">Three</Link>
        <div>選擇一個點擊</div>
        <Route path="/nested/:minooo?" render={({match}) => <h2>URL: {match.params.minooo || 'minooo'}</h2>} />
      </div>
    )
    return (
      <div className="App">
        <Router>
          <Link to="/">Home</Link>
          <Link to={{ pathname: '/about',search:'?sort=name', state:{ price: 18 } }}>About</Link>
          <Link to="/contact/12?name=minooo">Contact</Link>
          <Link to="/blog">blog</Link>
          <Link to="/nested">Nested</Link>
          {/* <NavLink to="/about" activeClassName="active">MyBlog</NavLink> */}
        <main>
          <Switch>
            <Route exact path="/" component={Home} />
              <Route path="/about" component={About} />
            <Route path="/contact/:id" render={({ history, location, match }) =>
              <h1>
                {console.log(history, location, match)}
                <span onClick={() => {history.push('/', {name:'mm'})}}>click me</span>
              </h1>} />
              <Route path="/blog" children={({ match }) => (
                <li className={match?'active': ''}>
                  <Link to="/">User</Link>
                </li>
            )} />
              <Route path="/nested" render={Nested} />
              <Route render={() => <h1>Page not found</h1>} />
            </Switch>
            </main>
        </Router>
      </div>
    );
  }
}
export default App;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章