一,使用createBrowserHistory 和 createHashHistory 的 區別體現
1. 使用createBrowserHistory ()
// 使用createBrowserHistory的代碼 import React from 'react'; import { Router, Route, Switch} from 'react-router-dom'; import { createHashHistory, createMemoryHistory, createBrowserHistory} from 'history'; import First from './container/First'; import Second from './container/Second'; import Third from './container/Third'; import Fourth from './container/Fourth'; const router = (props) => { return ( <Router history={createBrowserHistory()}> <Switch> <Route exact path={"/"} component={First} /> <Route exact path={"/first"} component={First} /> <Route exact path={"/second"} component={Second} /> <Route exact path={"/third"} component={Third} /> <Route exact path={"/fourth"} component={Fourth} /> </Switch> </Router> ) } export default router;
使用createBrowserHistory(),效果如下:
2. 使用createHashHistory()
//使用createHashHistory const router = (props) => { return ( <Router history={createHashHistory()}> <Switch> <Route exact path={"/"} component={First} /> <Route exact path={"/first"} component={First} /> <Route exact path={"/second"} component={Second} /> <Route exact path={"/third"} component={Third} /> <Route exact path={"/fourth"} component={Fourth} /> </Switch> </Router> ) } export default router;
使用createHashHistory(),效果如下:
3. 通過上面的對比, 可以發現
createBrowserHistory() 和 createHashHistory() 的區別體現在 打開頁面的路徑上:
createBrowserHistory: http://localhost:8084/second
createHashHistory: http://localhost:8084/#/second
還有一個 createMemoryHistory
——現在來看看官方介紹:
- “browser history” - A DOM-specific implementation, useful in web browsers that support the HTML5 history API
- “hash history” - A DOM-specific implementation for legacy web browsers
- “memory history” - An in-memory history implementation, useful in testing and non-DOM environments like React Native
browserHistory: 是使用瀏覽器中的 History API 來處理 URL(使用 React Router 推薦的 history)
hashHistory: 是使用 URL 中的 hash(#)部分去創建路由
memoryHistory: 未使用,不做介紹
二,browserHistory 和 hashHistory 的優缺點比較
1. 先看看官方推薦的 browserHistory
browserHistory 是使用 React-Router 的應用推薦的 history方案。它使用瀏覽器中的 History API 用於處理 URL,創建一個像example.com/list/123這樣真實的 URL 。
(摘自http://react-guide.github.io/react-router-cn/docs/guides/basics/Histories.html)
因為是使用真實的瀏覽器history,就像HTML網頁間的跳轉一樣,和瀏覽器的操作配合完美(瀏覽器自帶的“后退”,“前進”,“刷新” 按鈕,瀏覽器會記錄瀏覽history)
另外:此處需要解釋一下單頁面應用(SPA)和多頁面應用(MPA):
1)多頁面模式(MPA Multi-page Application):
多頁面跳轉需要刷新所有資源,每個公共資源(js、css等)需選擇性重新加載
頁面跳轉:使用window.location.href = "./index.html"進行頁面間的跳轉;
數據傳遞:可以使用path?account="123"&password=""路徑攜帶數據傳遞的方式,或者localstorage、cookie等存儲方式2)單頁面模式(SPA Single-page Application):
只有一個Web頁面的應用,是一種從Web服務器加載的富客戶端,單頁面跳轉僅刷新局部資源 ,公共資源(js、css等)僅需加載一次
頁面跳轉:使用js中的append/remove或者show/hide的方式來進行頁面內容的更換;
數據傳遞:可通過全局變量或者參數傳遞,進行相關數據交互
多頁面模式,就是多個HTML頁面之間的操作,瀏覽器會通過自身的history處理好頁面間的操作,
單頁面模式,對於瀏覽器來說只有一個HTML頁面,任何操作都在同一個頁面內,瀏覽器無法監控到頁面跳轉(實際只是內容改變,路徑沒變)
在單頁面模式下使用browserHistory 的問題是:只有一個真實的html頁面,是無法體現出html頁面之間跳轉的效果的
這時就需要使用服務器配合,模擬出多個HTML頁面,從而實現瀏覽器真實的頁面跳轉效果
2. 問題展示:
——在webpack 的 本地服務器模式下(webpack-dev-server插件模擬的本地服務器 )
未開啟historyApiFallback:
// 本地服務器 webpack-dev-server插件,開發中server,便於開發,可以熱加載 devServer: { contentBase: './dist', //默認本地服務器所在的根目錄 //historyApiFallback: true, inline: true, //源文件改變時刷新頁面 port: 8084 //端口號,默認8080 },
開啟historyApiFallback:
// 本地服務器 webpack-dev-server插件,開發中server,便於開發,可以熱加載 devServer: { contentBase: './dist', //默認本地服務器所在的根目錄 historyApiFallback: true, //開啟 inline: true, //源文件改變時刷新頁面 port: 8084 //端口號,默認8080 },
由此可見webpack-dev-server 中 設置 historyApiFallback 可以解決browserHistory 的問題
historyApiFallback 功能:
當使用 HTML5 History API 時,任意的
404
響應都可能需要被替代為index.html
三,那么,非開發模式(打出來的包)怎么辦??
方法一: 使用服務器進行相關配置,配合browserHistory進行使用
可以參考這篇文章: https://www.thinktxt.com/react/2017/02/26/react-router-browserHistory-refresh-404-solution.html
其實,就是通過服務器(無論Nginx,還是Node都可以)在瀏覽器方法該目錄下(比如dist文件夾)的文件時,都返回 index.html,
比如訪問 example.com/list/123 路徑,
- 但是服務器下沒有這個文件可供訪問,
- 所以就需要通過設置服務器,當瀏覽器訪問不存在的頁面時,都給索引到 index.html
- 在index.html 我們的browserHistory 才能派上用場
方法二: 使用HashRouter,雖然路徑 http://localhost:8084/#/second 多個‘#’,雖然項目內跳轉頁面可能會有問題。。。
如果有服務器端的動態支持,建議使用 BrowserRouter,否則建議使用 HashRouter。