React Router 之 browserHistory

前端工程采用 SPA 模式 hashHistory , 在集成到生產(chǎn)環(huán)境中的時(shí)候,使用browserHistory :

var his;
if (isDev) {
  //SPA
  his = hashHistory
} else {
  his = browserHistory
}

let routes =
  <Route path="/">
    <IndexRedirect to="index"/>
    <Route path="index" component={PageHome}/>
    <Route path="article_list" component={PageArticleList}/>
    <Route path="category_list" component={PageCategoryList}/>
    <Route path="tag_list" component={PageTagList}/>
  </Route>

let router = <Router routes={routes} history={his}/>
ReactDOM.render(router, document.getElementById('App'))

Histories

需要依賴: ReactRouter.min.js

Histories

React Router 是建立在 history 之上的。
簡(jiǎn)而言之,一個(gè) history 知道如何去監(jiān)聽(tīng)瀏覽器地址欄的變化,
并解析這個(gè) URL 轉(zhuǎn)化為 location 對(duì)象,
然后 router 使用它匹配到路由,最后正確地渲染對(duì)應(yīng)的組件。

常用的 history 有三種形式,
但是你也可以使用 React Router 實(shí)現(xiàn)自定義的 history。

你可以從 React Router 中引入它們:

// JavaScript 模塊導(dǎo)入(譯者注:ES6 形式)
import { browserHistory } from 'react-router'

然后將它們傳遞給<Router>:

render(
  <Router history={browserHistory} routes={routes} />,
  document.getElementById('app')
)

browserHistory

Browser history 是使用 React Router 的應(yīng)用推薦的 history。它使用瀏覽器中的 History API 用于處理 URL,創(chuàng)建一個(gè)像example.com/some/path這樣真實(shí)的 URL 。

服務(wù)器配置

服務(wù)器需要做好處理 URL 的準(zhǔn)備。處理應(yīng)用啟動(dòng)最初的 / 這樣的請(qǐng)求應(yīng)該沒(méi)問(wèn)題,但當(dāng)用戶來(lái)回跳轉(zhuǎn)并在 /accounts/123 刷新時(shí),服務(wù)器就會(huì)收到來(lái)自 /accounts/123 的請(qǐng)求,這時(shí)你需要處理這個(gè) URL 并在響應(yīng)中包含 JavaScript 應(yīng)用代碼。

一個(gè) express 的應(yīng)用可能看起來(lái)像這樣的:

const express = require('express')
const path = require('path')
const port = process.env.PORT || 8080
const app = express()

// 通常用于加載靜態(tài)資源
app.use(express.static(__dirname + '/public'))

// 在你應(yīng)用 JavaScript 文件中包含了一個(gè) script 標(biāo)簽
// 的 index.html 中處理任何一個(gè) route
app.get('*', function (request, response){
  response.sendFile(path.resolve(__dirname, 'public', 'index.html'))
})

app.listen(port)
console.log("server started on port " + port)

如果你的服務(wù)器是 nginx,請(qǐng)使用 try_files 指令

server {
  ...
  location / {
    try_files $uri /index.html
  }
}

當(dāng)在服務(wù)器上找不到其他文件時(shí),這可以讓 nginx 服務(wù)器提供靜態(tài)文件服務(wù)并指向index.html 文件。

對(duì)于Apache服務(wù)器也有類似的方式,創(chuàng)建一個(gè).htaccess文件在你的文件根目錄下:

RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]

IE8, IE9 支持情況

如果我們能使用瀏覽器自帶的 window.history API,那么我們的特性就可以被瀏覽器所檢測(cè)到。如果不能,那么任何調(diào)用跳轉(zhuǎn)的應(yīng)用就會(huì)導(dǎo)致 全頁(yè)面刷新,它允許在構(gòu)建應(yīng)用和更新瀏覽器時(shí)會(huì)有一個(gè)更好的用戶體驗(yàn),但仍然支持的是舊版的。

你可能會(huì)想為什么我們不后退到 hash history,問(wèn)題是這些 URL 是不確定的。如果一個(gè)訪客在 hash history 和 browser history 上共享一個(gè) URL,然后他們也共享同一個(gè)后退功能,最后我們會(huì)以產(chǎn)生笛卡爾積數(shù)量級(jí)的、無(wú)限多的 URL 而崩潰。

hashHistory

Hash history 使用 URL 中的 hash(#)部分去創(chuàng)建形如 example.com/#/some/path 的路由。

我應(yīng)該使用 createHashHistory嗎?

Hash history 不需要服務(wù)器任何配置就可以運(yùn)行,如果你剛剛?cè)腴T,那就使用它吧。但是我們不推薦在實(shí)際線上環(huán)境中用到它,因?yàn)槊恳粋€(gè) web 應(yīng)用都應(yīng)該渴望使用 browserHistory。

像這樣 ?_k=ckuvup 沒(méi)用的在 URL 中是什么?

當(dāng)一個(gè) history 通過(guò)應(yīng)用程序的 pushreplace 跳轉(zhuǎn)時(shí),它可以在新的 location 中存儲(chǔ) “l(fā)ocation state” 而不顯示在 URL 中,這就像是在一個(gè) HTML 中 post 的表單數(shù)據(jù)。

在 DOM API 中,這些 hash history 通過(guò) window.location.hash = newHash 很簡(jiǎn)單地被用于跳轉(zhuǎn),且不用存儲(chǔ)它們的location state。但我們想全部的 history 都能夠使用location state,因此我們要為每一個(gè) location 創(chuàng)建一個(gè)唯一的 key,并把它們的狀態(tài)存儲(chǔ)在 session storage 中。當(dāng)訪客點(diǎn)擊“后退”和“前進(jìn)”時(shí),我們就會(huì)有一個(gè)機(jī)制去恢復(fù)這些 location state。

createMemoryHistory

Memory history 不會(huì)在地址欄被操作或讀取。這就解釋了我們是如何實(shí)現(xiàn)服務(wù)器渲染的。同時(shí)它也非常適合測(cè)試和其他的渲染環(huán)境(像 React Native )。

和另外兩種history的一點(diǎn)不同是你必須創(chuàng)建它,這種方式便于測(cè)試。

const history = createMemoryHistory(location)

實(shí)現(xiàn)示例

import React from 'react'
import { render } from 'react-dom'
import { browserHistory, Router, Route, IndexRoute } from 'react-router'

import App from '../components/App'
import Home from '../components/Home'
import About from '../components/About'
import Features from '../components/Features'

render(
  <Router history={browserHistory}>
    <Route path='/' component={App}>
      <IndexRoute component={Home} />
      <Route path='about' component={About} />
      <Route path='features' component={Features} />
    </Route>
  </Router>,
  document.getElementById('app')
)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 本文翻譯自[https://medium.com/@pshrmn/a-little-bit-of-history-...
    jochenshi閱讀 15,188評(píng)論 0 16
  • React Router 4.0 (以下簡(jiǎn)稱 RR4) 已經(jīng)正式發(fā)布,它遵循React的設(shè)計(jì)理念,即萬(wàn)物皆組件。所...
    梁相輝閱讀 98,086評(píng)論 24 195
  • 一、基本用法 React Router 安裝命令如下。 $ npm install -S react-router...
    sunnyghx閱讀 4,601評(píng)論 0 6
  • 在這個(gè)教程里,我們會(huì)從一個(gè)例子React應(yīng)用開(kāi)始學(xué)習(xí)react-router-dom。其中你會(huì)學(xué)習(xí)如何使用Link...
    uncle_charlie閱讀 34,812評(píng)論 1 40
  • React-Router v4 1. 設(shè)計(jì)理念1.1. 動(dòng)態(tài)路由1.2. 嵌套路由1.3. 響應(yīng)式路由 2. 快速...
    wlszouc閱讀 8,740評(píng)論 0 14

友情鏈接更多精彩內(nèi)容