基於 React 的前端項目開發總結

原文發表於【抹橋的博客-基於 React 的前端項目開發總結】css

技術選型

咱們的項目主要選用如下技術開發,再配合一些其它輔助工具。html

  • react前端

  • react-routernode

  • reduxreact

  • react-reduxwebpack

開發及線上環境

開發環境

因爲項目是先後端分離的,因此咱們須要一套完整的開發環境,須要包括如下功能:nginx

  • 數據 Mockweb

  • Webpack 實施編譯刷新redux

  • 方便先後端聯調後端

基於這些需求,咱們基於 Express, Webpack, Webpack-dev-middleware 搭建了這套完整的開發環境。

圖片描述

能夠看到,瀏覽器全部的請求都被本地的 Node.js 服務攔截。對於靜態資源請求,都委託給 webpack-dev-middleware 來處理,對於接口請求根據不一樣的環境來決定要作的操做。

本地開發

ENV = 'development' 時,也就是開發環境,那麼就直接讀取本地的 mock 數據來渲染頁面。

先後端聯調

ENV = 'api' 時,也就是咱們認爲的聯調環境,這個時候對於接口請求由 node.js 轉發到須要聯調的真實後端服務地址上,從而避免直接調用所產生的跨域問題。

這樣就能夠直接用本地開發代碼和後端聯調,能大大提升效率,省去了每次須要往服務器上構建部署的步驟。

線上環境

先後端是分開部署的,全部的靜態資源都放在 CDN (example.cdn.com)上面。

也就是說咱們的頁面在 example.cdn/index.html 這裏,可是請求的接口在 example.163.com/api/xxx,咱們確定不能讓用戶去直接去訪問 example.cdn.com/index.html,這樣不合理,並且由跨域問題存在。

那麼訪問 example.dai.163.com 的時候,怎麼拿到咱們的 HTML 頁面呢?
看下圖:

線上環境

在客戶端和後臺服務之間架設一臺 Nginx, 咱們訪問的 example.dai.163.com 有兩種請求:

  • HTML 頁面資源

  • 接口請求

這兩種請求都先通過 nginx,在這裏作判斷,若是是頁面請求那麼由 nginx 轉發到 CDN, 不然交給後端服務來響應接口請求。

拿到頁面之後,其它全部的 css, js 等靜態資源都是直接請求到 CDN ,這裏沒什麼說的。

數據流轉

咱們是藉助 redux 來管理數據流的。

數據流轉

咱們來看這張圖。

首先,經過 middlewarereducer 生成 store, 而後得到項目的初始 state,經過初始 state 去渲染頁面的初始狀態。

Home 頁面爲例,首先 Home 經過 react-redux 提供的 connect 方法拿到初始 state 做爲 Homeprop 傳遞給 Home. 而 Home 由多個不一樣的子組件組成,這些組件的須要數據再由 Home 經過 props 傳遞給本身的子組件。

Home 的初始狀態加載完畢後,咱們須要向後端請求去拿去一些用戶數據。這時,咱們分發一個下面這種格式的 action:

{
  types: ['home/start','home/success','home/failure'],
  payload: {
    api:
    ...
  },
  meta: {
    isApi: true
  }
}

全部的 action 都會按照咱們制定的循序經過一個個 middleware.

在這裏,咱們的 action 會被 callApiMiddleware 經過 meta 裏面的 isApi 標識命中,並去作相應的事情。

好比在這個中間件裏面,咱們去作了真實的接口請求,在請求成功或失敗的時候分發對應的 action,以及作一些統一的業務邏輯。好比咱們對後端返回的接口中 code 值有統一的約定,假設 1 爲成功, 2 爲失敗, 3 爲未登陸。那麼咱們就能夠在中間件中去處理這些業務邏輯。

當請求成功,並渲染頁面後,假設用戶點擊了一個按鈕,這個按鈕須要喚起 native 的一些功能,好比說拍照。那麼咱們分發一個喚起拍照功能的 camera/startaction:

{
  types: ['sdk/start','sdk/success','sdk/failure'],
  payload: {
    command:
    ...
  },
  meta: {
    isSDK: true
  }
}

一樣的道理,這個 action 會被 EpaySDKMiddleware 所識別並處理,在調起 native 的時候, 爲了保證安全性,咱們須要向後發起一個請求去拿簽名,這個時候就能夠在 EpaySDKMiddleware 裏面分發一個接口請求的 action,那麼這個 action 一樣須要走一遍全部的 middleware. 那麼這個接口請求的 action 就會像上面的流程同樣,經過 callApiMiddleware 去處理。

中間件的存在,使整個流程變得很是清晰,接口的請求的中間件就只作接口請求,調用 native 接口的中間件就只作對 native 的調用,當對 native 接口的調用須要作後端接口請求的時候,去分發一個 action 走接口請求的中間件。

每一箇中間件只專一於本身的事情,既方便後續的維護,同時也提供了一個很好的拓展方式。

一個例子

總體流程

假設咱們由以下的一個路由配置。

{
    component: App,
    path: '/',
    onEnter: initLogin(store),
    indexRoute: {
      getComponent(nextState, cb) {
        require.ensure([], require => {
          cb(null, require('../views/Home').default)
        }, 'Home')
      },
      onEnter: initHome(store)
    },
    childRoutes: [
      createActivateRoute(store),
      {
        path: 'test',
        indexRoute: {
          getComponent(nextState, cb) {
            require.ensure([], require => {
              cb(null, require('../views/Test').default)
            }, 'Test')
          }
        }
      },
      ...
    ]
}

那結合 react-route 咱們來看一個完整的流程。當咱們瀏覽器裏面輸入 example.dai.163.com/index.html/#/ 的時候。

首先,經過最上面 線上環境 一節提到的內容,拿到頁面須要 html,css,js.

而後渲染 ProvideRouter 組件,分別提供 store 的注入和路由的控制。

此時觸發根路徑的路由匹配,而後加載根組件 APP, 而後根據路由匹配規則匹配到 IndexRouter, 加載 Home 組件。

後面的事情就和前面數據流轉一節講的是同樣的了。

總結

在先後端徹底分離的基礎上,藉助一套完善的開發環境,能夠大大提升的咱們的開發效率,下降先後端聯調的成本。

同時藉助於 Redux 思想,實現單向數據流,讓咱們能夠實現一個很是清晰的數據流向。而且,藉助於中間件,咱們能夠更加有效的控制數據流轉的過程。爲後面項目的擴展提供無限的想象空間。

相關文章
相關標籤/搜索