react-router-dom和本地服務本地開發 (node、webpack)

場景

使用react 作開發,避免會使用react-routercss

React Router 已是V4的版本

React Router 目前已經被劃分紅了三個包:react-routerreact-router-dom, react-router-native
React Router 應用提供了核心的路由組件和函數,另外兩個包提供了特定環境的組件(瀏覽器和 react-native 對應的平臺),不過他們也是將 react-router 導出的模塊再次導出。html

> 本文核心要講的就是react-router-dom 和 本地服務的故事

react-router-dom做爲瀏覽器的平臺,是咱們的作WEB首選。react-router-dom能夠選擇 <BrowserRouter><HashRouter> 組件前端

<BrowserRouter> 應該用在服務器處理動態請求的項目中(知道如何處理任意的URI)
<HashRouter> 用來處理靜態頁面(只能響應請求已知文件的請求)。node

假若有一個 Link 標籤,點擊後跳轉到 /test/guide。react

BrowserRouter: http://localhost:8080/test/guide
HashRouter: http://localhost:8080/#/test/guidewebpack

一般來講更推薦使用 ,但是若是服務器只處理靜態頁面的請求,那麼使用 也是一個足夠的解決方案。 web

關於本地服務

現現在,前端開發避免不了本地服務開發,大多數會選擇node作本地服務開發層,其中包括了koa,express。webpack作本地服務webpack-dev-server(也是一個express的服務)
有本地服務就避免不了本地路由。本地服務的get URL請求如何和react-router作適配呢?請往下看。express

關於HashRouter 和本地服務

HashRouter作本地開發,主要是 hash 地址,hash 地址就是指 # 號後面的 url。這個功能只會實現靜態頁面的跳轉,不會產生路由的變化
如上面例子HashRouter: http://localhost:8080/#/test/guide,對於服務端而言,路由實際仍是再根目錄下'/' ,而「#/test/guide」 只是hash地址,能夠經過瀏覽器location 命令查看
由於對於服務端而言,路由實際上沒有發生GET請求變化,以致於服務端不會發生響應,也不會存在Cannot GET頁面提示404等問題。react-native

其中若是是webpack服務,關於設置historyApiFallback:true 網上有不少的文章,給了這個答案,來處理本地服務問題promise

首先 devServer.historyApiFallback 用來應對返回404頁面時定向到特定頁面用的

若是你在webpack配置文件中修改了 output.publicPath 值默認爲'/',那麼你就須要聲明請求重定向,配置historyApiFallback.index 值。

// output.publicPath: '/assets/'
historyApiFallback: {
 index: '/assets/'
}

關於BrowserRouter 和本地服務
由上面的例子BrowserRouter: http://localhost:8080/test/guide,可見,使用BrowserRouter,history對url連接進行了處理,當連接跳轉以後,若是對頁面進行刷新reload操做,那麼本地服務
就會捕獲到路由的GET請求,這就是問題的關鍵,須要本地服務對請求進行處理,方式有不少,這裏介紹一種比較籠統直接的方式;

const router = express.Router();
const request = require("request-promise").defaults({ jar: true });

router.all("*", async (req, res, next) => {
    let url = req.url; //頁面連接上的url
    let html = "";

    // 不匹配如下路由規則,只匹配URL GET請求
    if (url.match(/\.(png|jpe?g|gif|js|css|html|ico)/)) {
        return next();
    }

    html = await reactRoute().catch(e => {
      //do error handle
      return false;
    });

    if(html){
        return res.send(html);
    }

    //其餘路由處理規則...
    return next();
})


async function reactRoute() {
  return new Promise((resolve, reject) => {

    //這裏能夠作一層非react項目的過濾,這裏不重要
    // if(noReact){
    //  reject('no react url')
    // }

    let html = await request({
      method: "get",
      url: `http://localhost:8080/pages/index.html` //本地服務index路徑(爲react配置的BrowserRouter路徑),因項目而異,只是一個例子
    }).catch(e => {
      reject(e);
    });

    resolve(html);
  })
}

以上代碼的邏輯是,本地服務,讀取URL get請求,若是本地服務請求404,那麼把react 的BrowserRouter 啓動文件返回,該文件應該是本地服務能夠讀取到的html文件。
如下是圖解

相關文章
相關標籤/搜索