React List - React Router

jsliang發表於2019-04-29

Create by jsliang on 2019-04-26 13:13:18
Recently revised in 2019-04-29 15:25:01

Hello 小夥伴們,如果覺得本文還不錯,記得給個 star , 小夥伴們的 star 是我持續更新的動力!GitHub 地址

一 目錄

不折騰的前端,和鹹魚有什麼區別

目錄
一 目錄
二 前言
三 初試
四 簡介
五 BrowserRouter
5.1 BrowserRouter 語法
5.2 BrowserRouter - basename
5.3 BrowserRouter - getUserConfirmation
5.4 BrowserRouter - forceRefresh
5.5 BrowserRouter - keyLength
六 HashRouter
6.1 HashRouter - basename
6.2 HashRouter - getUserConfirmation
6.3 HashRouter - hashType
七 Link
7.1 Link - to
7.2 Link - replace
7.3 Link - other
八 NavLink
8.1 NavLink - activeClassName
8.2 NavLink - activeStyle
8.3 NavLink - exact
8.4 NavLink - isActive
九 MemoryRouter
9.1 MemoryRouter - initialEntries
9.2 MemoryRouter - initialIndex
9.3 MemoryRouter - getUserConfirmation
9.4 MemoryRouter - keyLength
十 Redirect
10.1 Redirect - from
10.2 Redirect - to
10.3 Redirect - push
10.4 Redirect - exact
十一 Route
11.1 Route - component
11.2 Route - render
11.3 Route - children
11.4 Route - path
11.5 Route - exact
11.6 Route - location
11.7 Route - sensitive
十二 Switch
十三 篇外一:history
十四 篇外二:Code Splitting
十五 篇外三:Scroll To Top
15.1 跳轉頁面後滾動到頂部
15.2 頁面滾動到頂部
十六 篇外四:Redux
十七 總結

二 前言

返回目錄

前端路由,是指改變 URL 路徑的形式,從而切換到不同的頁面,例如:

  • localhost:3000/home
  • localhost:3000/user

通過切換不同的 URL,顯示不同的頁面,從而有了 路由 的概念。

這篇文章我們講解在 React 中如何通過 React Router 這個外掛,靈活使用路由。

jsliang 瞎吹的,最好自己百度 前端路由 是啥。

  • 參考資料:
  1. React Router 官方文件
  2. React Router 中文文件
  3. React Router 中文文件(舊)
  4. React Router DOM 中文文件(一) - 簡書
  5. React Router DOM 中文文件(二) - 簡書
  • 篇外話題:

網上有很多 React Router 文章了,例如:

為何 jsliang 要多次一舉?

  1. 你記錄你的,我記錄我的,互相不妨礙。
  2. 看這些跟看官網沒啥兩樣,所以我需要親自動手過一遍官網。
  3. 記錄我看官網的內容,順帶記錄我應用上去的例項,方便我下次回顧。

三 初試

返回目錄

當前版本"react-router-dom": "^5.0.0"

首先,在 Create React App 中,我們引用 React Router:

  • npm i react-router-dom -S

然後,在 src 目錄下新建 pages 用來存放頁面,並修改 App.js:

案例:App.js

import React, { Fragment } from 'react';
import { BrowserRouter, Route, Switch, Redirect } from 'react-router-dom';
import ScrollToTop from './components/ScrollToTop';
import Header from './components/Header';
import TimeLine from './pages/TimeLine';
import NotFound from './pages/404';

function App() {
  return (
    <Fragment>
      <BrowserRouter>
        <Header />
        <ScrollToTop>
          <Switch>
            <Redirect from="/" to="/timeline" exact />
            <Route path="/timeline" component={TimeLine}></Route>
            <Route component={NotFound}></Route>
          </Switch>
        </ScrollToTop>
      </BrowserRouter>
    </Fragment>
  );
}

export default App;
複製程式碼

最後,通過在 App.js 中如此定義,即可定義對應的元件,並渲染對應頁面和進行跳轉。

四 簡介

返回目錄

下面我們拿一些常用的進行介紹:

import { 
  BrowserRouter,
  HashRouter,
  Redirect,
  Route,
  NavLink,
  Link,
  MemoryRouter,
  Switch,
  withRouter
} from "react-router-dom";
複製程式碼
  1. <BrowserRouter>:路由元件包裹層。<Route><Link> 的包裹層。
  2. <HashRouter>:路由元件包裹層。相對於 <BrowserRouter> 來說,更適合靜態檔案的伺服器。
  3. <Redirect>:路由重定向。渲染 <Redirect> 將使導航到一個新的地址。
  4. <Route>:路由。定義一個路由頁面,用來匹配對應的元件(Component)和路由路徑。
  5. <NavLink>:活躍連結。當 URL 中的路徑等於該路由定義的路徑時,該標籤可以呈現它定義的 activeClassName
  6. <Link>:連結。用來跳轉到 <Route> 對應的路由(Component) 中。
  7. <MemoryRouter>:暫未使用。<Router> 能在記憶體中儲存 URL 的歷史記錄。很適合在測試環境和非瀏覽器環境中使用,例如 React Native。
  8. <Switch>:路由分組。渲染與該地址匹配的第一個子節點 <Route>或者 <Redirect>。可以利用 <Switch> 做分組。
  9. <withRouter>:路由組合。通過 <withRouter> 高階元件訪問 history 物件的屬性和最近的 <Route>match。或者利用它來結合 Redux。

五 BrowserRouter

返回目錄

<BrowserRouter> 會為你建立一個專門的 history 物件,用來記錄你的路由,從而能夠返回上一頁或者跳轉到指定的路由頁面。

區別於 <HashRouter>,有響應請求的伺服器時使用 <BrowserRouter>,使用的是靜態檔案的伺服器,則用 <HashRouter>

簡單案例:

<BrowserRouter>
  <Header />
  <Route path="/" exact component={TimeLine}></Route>
  <Route path="/timeline" component={TimeLine}></Route>
</BrowserRouter>
複製程式碼

5.1 BrowserRouter 語法

返回目錄

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

<BrowserRouter
  basename={optionalString}
  forceRefresh={optionalBool}
  getUserConfirmation={optionalFunc}
  keyLength={optionalNumber}
>
  <App/>
</BrowserRouter>
複製程式碼

5.2 BrowserRouter - basename

返回目錄

  • 規則:basename: string

為裡面的子目錄提供基礎路徑名,例如:

<BrowserRouter basename="/calendar">
  <Link to="/today"/> 
  {/* 渲染為 <a href="/calendar/today"> */}
</BrowserRouter>
複製程式碼

5.3 BrowserRouter - getUserConfirmation

返回目錄

  • 規則:getUserConfirmation: function

用於確認導航的功能。

// 預設使用 window.confirm。
const getConfirmation = (message, callback) => {
  const allowTransition = window.confirm(message)
  callback(allowTransition)
}

<BrowserRouter getUserConfirmation={getConfirmation}/>
複製程式碼

5.4 BrowserRouter - forceRefresh

返回目錄

  • 規則:forceRefresh: bool

如果為 true,則路由器將在頁面導航中使用整頁重新整理

const supportsHistory = 'pushState' in window.history
<BrowserRouter forceRefresh={!supportsHistory}/>
複製程式碼

5.5 BrowserRouter - keyLength

返回目錄

  • 規則:keyLength: number

設定它裡面路由的 location.key 的長度。預設為 6。

key 的作用:點選同一個連結時,每次該路由下的 location.key都會改變,可以通過 key 的變化來重新整理頁面。

<BrowserRouter keyLength={12}/>
複製程式碼

六 HashRouter

返回目錄

使用 URLhash 部分(即 window.location.hash )的 <Router> 使 UIURL 保持同步。

重要提示:Hash 歷史記錄不支援 location.keylocation.state

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

<HashRouter>
  <App/>
</HashRouter>
複製程式碼

6.1 HashRouter - basename

返回目錄

  • 規則:basename: string

所有位置的基本 URL,格式正確的基本名應該有一個前導斜線,但結尾不能有斜線。

<HashRouter basename="/calendar"/>
<Link to="/today"/> 
{/* 渲染為 <a href="/calendar/today"> */}
複製程式碼

6.2 HashRouter - getUserConfirmation

返回目錄

  • 規則:getUserConfirmation: func

用於確認導航的功能。預設使用 window.confirm。

// this is the default behavior
const getConfirmation = (message, callback) => {
  const allowTransition = window.confirm(message)
  callback(allowTransition)
}

<HashRouter getUserConfirmation={getConfirmation}/>
複製程式碼

6.3 HashRouter - hashType

返回目錄

  • 規則:hashType: string

用於 window.location.hash 的編碼型別。可用的值是:

  • slash - 建立 #/ 和的 #/sunshine/lollipops
  • noslash - 建立 # 和的 #sunshine/lollipops
  • hashbang - 建立 ajax crawlable,如 #!/#!/sunshine/lollipops

預設為 slash

七 Link

返回目錄

在應用程式周圍提供宣告式的,可訪問的導航。

7.1 Link - to

返回目錄

  • 規則 1:to: string

連結位置的字串表示,通過連線位置的路徑名,搜尋和 hash 屬性建立。

<Link to='/courses?sort=name'>字串形式跳轉</Link>
複製程式碼
  • 規則 2:to: object

一個可以具有以下任何屬性的物件:

  • pathname: 表示要連結到的路徑的字串。
  • search: 表示查詢引數的字串形式。
  • hash: 放入網址的 hash,例如 #a-hash
  • state: 狀態持續到 location
<Link to={{
  pathname: '/courses',          // 基礎路徑
  search: '?sort=name',          // 匹配欄位
  hash: '#the-hash',             // 對應內鏈
  state: { fromDashboard: true } // 未知
}}>
  物件形式跳轉
</Link>
複製程式碼

7.2 Link - replace

返回目錄

  • 規則:replace: bool

如果為 true,則單擊連結將替換歷史堆疊中的當前入口,而不是新增新入口。

<Link to="/courses" replace>替換當前 hash 路徑</Link>
複製程式碼

7.3 Link - other

返回目錄

還可以傳遞想要放在 <a> 上的屬性,例如標題,IDclassName 等。

<Link to="/test" id="myTest">測試 1</Link>
複製程式碼

返回目錄

八 NavLink

返回目錄

一個特殊版本的 Link,當它與當前 URL 匹配時,為其渲染元素新增樣式屬性。

  • 高亮顯示首頁:<NavLink to="/timeline" activeClassName="active">首頁</NavLink>

8.1 NavLink - activeClassName

返回目錄

  • 規則:activeClassName: string

要給出的元素的類處於活動狀態時。預設的給定類是 active。它將與 className 屬性一起使用。

<NavLink
  to="/faq"
  activeClassName="selected"
>FAQs</NavLink>
複製程式碼

8.2 NavLink - activeStyle

返回目錄

  • 規則:activeStyle: object

當元素處於 active 時應用於元素的樣式。

<NavLink
  to="/faq"
  activeStyle={{
    fontWeight: 'bold',
    color: 'red'
   }}
>FAQs</NavLink>
複製程式碼

8.3 NavLink - exact

返回目錄

  • 規則:exact: bool

如果為 true,則僅在位置完全匹配時才應用 active 的類/樣式。

<NavLink
  exact
  to="/profile"
>Profile</NavLink>
複製程式碼

8.4 NavLink - isActive

返回目錄

  • 規則:isActive: function

一個為了確定連結是否處於活動狀態而新增額外邏輯的函式,如果你想做的不僅僅是驗證連結的路徑名與當前 URL 的 pathname 是否匹配,那麼應該使用它

// 如果連結不僅僅匹配 events/123,而是所有奇數連結都匹配
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>
複製程式碼

九 MemoryRouter

返回目錄

<Router> 能在記憶體中儲存 URL 的歷史記錄(並不會對位址列進行讀寫)。很適合在測試環境和非瀏覽器環境中使用,例如 React Native。

<MemoryRouter>
  <App/>
</MemoryRouter>
複製程式碼

9.1 MemoryRouter - initialEntries

返回目錄

  • 規則:initialEntries: array

history 棧中的一個 location 陣列。這些可能是具有 { pathname, search, hash, state } 或簡單的 URL 字串的完整地址物件。

<MemoryRouter
  initialEntries={[ '/one', '/two', { pathname: '/three' } ]}
  initialIndex={1}
>
  <App/>
</MemoryRouter>
複製程式碼

9.2 MemoryRouter - initialIndex

返回目錄

  • 規則:initialIndex: number

initialEntries 陣列中的初始化地址索引。

9.3 MemoryRouter - getUserConfirmation

返回目錄

  • 規則:getUserConfirmation: function

用於確認導航的函式。在使用 <MemoryRouter> 時,直接使用 <Prompt>,你必須使用這個選項。

9.4 MemoryRouter - keyLength

返回目錄

  • 規則:keyLength: number

location.key的長度。預設為 6。

十 Redirect

返回目錄

渲染 <Redirect> 將使導航到一個新的地址。這個新的地址會覆蓋 history 棧中的當前地址,類似伺服器端(HTTP 3xx)的重定向。

我們可以設定某個路由重定向到另一個路由,例如下面即對 / 完全匹配重定向到 /timeline 頁面。

<Redirect from="/" to="/timeline" exact />
複製程式碼

10.1 Redirect - from

返回目錄

  • 規則:from: string

重定向 from 的路徑名。可以是任何 path-to-regexp 能夠識別的有效的 URL 路徑。

所有匹配的 URL 引數都提供給 to 中的模式。

必須包含在 to 中使用的所有引數。

to 未使用的其他引數將被忽略。

<Switch>
  <Redirect from="/old-path" to="/new-path" />
  <Route path="/new-path" component={Place} />
</Switch>
複製程式碼

10.2 Redirect - to

返回目錄

  • 規則:to: string

重定向到的 URL,可以是任何 path-to-regexp 能夠理解有效 URL 路徑。

to 中使用的 URL 引數必須由 from 覆蓋。

<Redirect to="/somewhere/else" />
複製程式碼
  • 規則:to: object

重定向到的 locationpathname 可以是任何 path-to-regexp 能夠理解的有效的 URL 路徑。

<Redirect
  to={{
    pathname: "/login",
    search: "?utm=your+face",
    state: { referrer: currentLocation }
  }}
/>
複製程式碼

10.3 Redirect - push

返回目錄

  • 規則:push: bool

true 時,重定向會將新地址推入 history 中,而不是替換當前地址。

<Redirect push to="/somewhere/else" />
複製程式碼

10.4 Redirect - exact

返回目錄

  • 規則:exact: bool

完全匹配 from

十一 Route

返回目錄

只要應用程式位置與 Route 的路徑匹配,元件就會被渲染。

11.1 Route - component

返回目錄

只有當位置匹配時才會渲染的 React 元件。

<Route path="/user/:username" component={User}/>

const User = ({ match }) => {
  return <h1>Hello {match.params.username}!</h1>
}
複製程式碼

11.2 Route - render

返回目錄

  • 規則:render: function

這允許方便的內聯渲染和包裹,而不是上面那種不想要的重新安裝的解釋

可以傳遞一個在位置匹配時呼叫的函式,而不是使用屬性為您建立新的 React element component,該 render 屬性接收所有相同的 route propscomponent 渲染屬性。

// 行內編寫
<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}/>
複製程式碼

11.3 Route - children

返回目錄

  • 規則:children: function

有時你需要渲染路徑是否匹配位置。在這些情況下,您可以使用函式 children 屬性,它的工作原理與渲染完全一樣,不同之處在於它是否存在匹配。

children 渲染道具接收所有相同的 route props 作為 componentrender 方法,如果 RouteURL 不匹配,match 則為 null ,這允許你動態調整你的 UI 介面,基於路線是否匹配,如果路線匹配我們則新增一個 active 類。

<ul>
  <ListItemLink to="/somewhere"/>
  <ListItemLink to="/somewhere-else"/>
</ul>

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

11.4 Route - path

返回目錄

  • 規則:path: string

任何 path-to-regexp 可以解析的有效的 URL 路徑

<Route path="/users/:id" component={User}/>
複製程式碼

11.5 Route - exact

返回目錄

  • 規則:exact: bool

如果為 true,則只有在路徑完全匹配 location.pathname 時才匹配。

path location.pathname exact matches?
/one /one/two true no
/one /one/two false yes
<Route exact path="/one" component={About}/>
複製程式碼

jsliang 個人經驗:

  1. 加了 exact 屬性後,會完全匹配路徑;如果沒有加,則二級路徑也會匹配當前路徑(例如 /timeline/book)。
<BrowserRouter>
  <Route path="/" exact component={TimeLine}></Route>
  <Route path="/timeline" component={TimeLine}></Route>
</BrowserRouter>
複製程式碼
  1. 我們可以動態設定 extra 的值,從而判斷是否需要載入某個元件。
const Home = () => <div>Home</div>;

const App = () => {
  const someVariable = true;

  return (
    <Switch>
      {/* these are good */}
      <Route exact path="/" component={Home} />
      <Route
        path="/about"
        render={props => <About {...props} extra={someVariable} />}
      />
      {/* do not do this */}
      <Route
        path="/contact"
        component={props => <Contact {...props} extra={someVariable} />}
      />
    </Switch>
  );
};
複製程式碼

11.6 Route - location

返回目錄

  • 規則:location: object

一個 <Route> 元素嘗試其匹配 path 到當前的歷史位置(通常是當前瀏覽器 URL)。但是,也可以通過location 一個不同 pathname 的匹配。

11.7 Route - sensitive

返回目錄

  • 規則:sensitive: bool

如果路徑區分大小寫,則為 true,則匹配。

path location.pathname sensitive matches?
/one /one true yes
/One /one true no
/One /one false yes
<Route sensitive path="/one" component={About}/>
複製程式碼

十二 Switch

返回目錄

渲染與該地址匹配的第一個子節點 <Route>或者 <Redirect>

可以利用 <Switch> 做分組,即當有匹配時,匹配對應 path 對應的元件;如果沒有匹配,則匹配 NotFound 頁面。

<BrowserRouter>
  <Header />
  <Switch>
    <Route path="/" exact component={TimeLine}></Route>
    <Route path="/timeline" component={TimeLine}></Route>
    <Route component={NotFound}></Route>
  </Switch>
</BrowserRouter>
複製程式碼

十三 篇外一:history

返回目錄

history 是一個包,在你安裝 React Router 的時候,會作為它依賴包安裝到專案中,所以你可以直接使用 history 中的屬性和方法:

  • length - (number 型別) history 堆疊的條目數
  • action - (string 型別) 當前的操作(push, replace, pop)
  • location - (object 型別) 當前的位置。location 會具有以下屬性:
    • pathname - (string 型別) URL 路徑
    • search - (string 型別) URL 中的查詢字串
    • hash - (string 型別) URL 的雜湊片段
    • state - (object 型別) 提供給例如使用 push(path, state) 操作將
  • location 放入堆疊時的特定 location 狀態。只在瀏覽器和記憶體歷史中可用
  • push(path, [state]) - (function 型別) 在 history 堆疊新增一個新條目
  • replace(path, [state]) - (function 型別) 替換在 history 堆疊中的當前條目
  • go(n) - (function 型別) 將 history 堆疊中的指標調整 n
  • goBack() - (function 型別) 等同於 go(-1)
  • goForward() - (function 型別) 等同於 go(1)
  • block(prompt) - (function 型別) 阻止跳轉

十四 篇外二:Code Splitting

返回目錄

隨著應用的增長,程式碼包會隨著生長。

到最後你會發現,你打包後的 js 檔案大地太多離譜。

所以,我們需要通過程式碼分割,依據不同的路由,載入不同的 js 檔案。

  1. 安裝 React Loadable:npm i react-loadable -S
  2. 結合 React Router 和 React Loadable 進行 Code Spliting:
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import Loadable from 'react-loadable';

const Loading = () => <div>Loading...</div>;

const Home = Loadable({
  loader: () => import('./routes/Home'),
  loading: Loading,
});

const About = Loadable({
  loader: () => import('./routes/About'),
  loading: Loading,
});

const App = () => (
  <Router>
    <Switch>
      <Route exact path="/" component={Home}/>
      <Route path="/about" component={About}/>
    </Switch>
  </Router>
);
複製程式碼
  1. 打包專案: npm run build

十五 篇外三:Scroll To Top

返回目錄

15.1 跳轉頁面後滾動到頂部

返回目錄

  1. 首先,在全域性 components 檔案中定義 ScrollToTop 資料夾,其中 index.js 內容為:

src/components/ScrollToTop/index.js

import { Component } from 'react';
import { withRouter } from 'react-router-dom';

class ScrollToTop extends Component {
    componentDidUpdate(prevProps) {
        if (this.props.location !== prevProps.location) {
          window.scrollTo(0, 0)
        }
    }
    render() {
        return this.props.children
    }
}
 
export default withRouter(ScrollToTop);
複製程式碼
  1. 然後,在 App.js 或者其他頁面中使用 ScrollToTop 功能:

src/App.js

import React, { Fragment } from 'react';
import { BrowserRouter, Route, Switch, Redirect } from 'react-router-dom';
import ScrollToTop from './components/ScrollToTop';
import Header from './components/Header';
import TimeLine from './pages/TimeLine';
import NotFound from './pages/404';

function App() {
  return (
    <Fragment>
      <BrowserRouter>
        <Header />
        <ScrollToTop>
          <Switch>
            <Redirect from="/" to="/timeline" exact />
            <Route path="/timeline" component={TimeLine}></Route>
            <Route component={NotFound}></Route>
          </Switch>
        </ScrollToTop>
      </BrowserRouter>
    </Fragment>
  );
}

export default App;
複製程式碼
  1. 最後,我們切換路由的時候,頁面就會滾動到頂部。

15.2 頁面滾動到頂部

返回目錄

暫未實現

十六 篇外四:Redux

返回目錄

在專案中,我們更希望 React Router 和 React Redux 合併起來,這時候可以:

// before
export default connect(mapStateToProps)(Something)

// after
import { withRouter } from 'react-router-dom'
export default withRouter(connect(mapStateToProps)(Something))
複製程式碼

十七 總結

返回目錄

如果你純粹過文件(官方文件,jsliang 的文件),你會覺得毫無趣味、了無生趣、乏味、沉悶……

所以,jsliang 的學法是:開啟了一個專案,邊翻閱文件,邊應用到專案中,並進行 Mark 標記,以便下次使用。

如此,該文件雖然完結了,但是仍未完結!完結的是我過完了官方文件,未完結的是 React Router 在我專案中可能有其他應用,需要我一一新增進來。


jsliang 廣告推送:
也許小夥伴想了解下雲伺服器
或者小夥伴想買一臺雲伺服器
或者小夥伴需要續費雲伺服器
歡迎點選 雲伺服器推廣 檢視!

React List - React Router
React List - React Router

知識共享許可協議
jsliang 的文件庫樑峻榮 採用 知識共享 署名-非商業性使用-相同方式共享 4.0 國際 許可協議進行許可。
基於github.com/LiangJunron…上的作品創作。
本許可協議授權之外的使用許可權可以從 creativecommons.org/licenses/by… 處獲得。

相關文章